aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN5
-rw-r--r--tools/perf/util/annotate.c76
-rw-r--r--tools/perf/util/annotate.h26
-rw-r--r--tools/perf/util/build-id.c6
-rw-r--r--tools/perf/util/build-id.h3
-rw-r--r--tools/perf/util/cache.h3
-rw-r--r--tools/perf/util/callchain.c147
-rw-r--r--tools/perf/util/callchain.h14
-rw-r--r--tools/perf/util/color.c11
-rw-r--r--tools/perf/util/color.h2
-rw-r--r--tools/perf/util/comm.c121
-rw-r--r--tools/perf/util/comm.h21
-rw-r--r--tools/perf/util/cpumap.c6
-rw-r--r--tools/perf/util/data.c120
-rw-r--r--tools/perf/util/data.h48
-rw-r--r--tools/perf/util/dso.c50
-rw-r--r--tools/perf/util/dso.h3
-rw-r--r--tools/perf/util/event.c124
-rw-r--r--tools/perf/util/event.h18
-rw-r--r--tools/perf/util/evlist.c301
-rw-r--r--tools/perf/util/evlist.h26
-rw-r--r--tools/perf/util/evsel.c43
-rw-r--r--tools/perf/util/evsel.h34
-rw-r--r--tools/perf/util/fs.c119
-rw-r--r--tools/perf/util/fs.h7
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh4
-rw-r--r--tools/perf/util/header.c26
-rw-r--r--tools/perf/util/hist.c95
-rw-r--r--tools/perf/util/hist.h88
-rw-r--r--tools/perf/util/include/dwarf-regs.h2
-rw-r--r--tools/perf/util/include/linux/compiler.h19
-rw-r--r--tools/perf/util/include/linux/magic.h4
-rw-r--r--tools/perf/util/intlist.c23
-rw-r--r--tools/perf/util/intlist.h2
-rw-r--r--tools/perf/util/machine.c180
-rw-r--r--tools/perf/util/machine.h41
-rw-r--r--tools/perf/util/map.c50
-rw-r--r--tools/perf/util/map.h7
-rw-r--r--tools/perf/util/parse-events.c10
-rw-r--r--tools/perf/util/parse-events.l63
-rw-r--r--tools/perf/util/parse-options.c218
-rw-r--r--tools/perf/util/parse-options.h4
-rw-r--r--tools/perf/util/path.c10
-rw-r--r--tools/perf/util/perf_regs.h4
-rw-r--r--tools/perf/util/pmu.c33
-rw-r--r--tools/perf/util/pmu.h1
-rw-r--r--tools/perf/util/probe-event.c5
-rw-r--r--tools/perf/util/probe-finder.c250
-rw-r--r--tools/perf/util/probe-finder.h15
-rw-r--r--tools/perf/util/pstack.h10
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/python.c10
-rw-r--r--tools/perf/util/rblist.c27
-rw-r--r--tools/perf/util/rblist.h1
-rw-r--r--tools/perf/util/record.c71
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c4
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c41
-rw-r--r--tools/perf/util/session.c278
-rw-r--r--tools/perf/util/session.h38
-rw-r--r--tools/perf/util/sort.c331
-rw-r--r--tools/perf/util/sort.h8
-rw-r--r--tools/perf/util/srcline.c265
-rw-r--r--tools/perf/util/strfilter.c72
-rw-r--r--tools/perf/util/strfilter.h12
-rw-r--r--tools/perf/util/symbol-elf.c607
-rw-r--r--tools/perf/util/symbol-minimal.c15
-rw-r--r--tools/perf/util/symbol.c449
-rw-r--r--tools/perf/util/symbol.h29
-rw-r--r--tools/perf/util/sysfs.c60
-rw-r--r--tools/perf/util/sysfs.h6
-rw-r--r--tools/perf/util/target.c54
-rw-r--r--tools/perf/util/target.h45
-rw-r--r--tools/perf/util/thread.c137
-rw-r--r--tools/perf/util/thread.h20
-rw-r--r--tools/perf/util/top.c2
-rw-r--r--tools/perf/util/top.h1
-rw-r--r--tools/perf/util/trace-event-parse.c36
-rw-r--r--tools/perf/util/trace-event.h9
-rw-r--r--tools/perf/util/unwind.c84
-rw-r--r--tools/perf/util/unwind.h9
-rw-r--r--tools/perf/util/util.c66
-rw-r--r--tools/perf/util/util.h26
82 files changed, 3896 insertions, 1417 deletions
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index 15a77b7c0e36..39f17507578d 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -19,6 +19,9 @@ if test -d ../../.git -o -f ../../.git
19then 19then
20 TAG=$(git describe --abbrev=0 --match "v[0-9].[0-9]*" 2>/dev/null ) 20 TAG=$(git describe --abbrev=0 --match "v[0-9].[0-9]*" 2>/dev/null )
21 CID=$(git log -1 --abbrev=4 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID" 21 CID=$(git log -1 --abbrev=4 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID"
22elif test -f ../../PERF-VERSION-FILE
23then
24 TAG=$(cut -d' ' -f3 ../../PERF-VERSION-FILE | sed -e 's/\"//g')
22fi 25fi
23if test -z "$TAG" 26if test -z "$TAG"
24then 27then
@@ -40,7 +43,7 @@ else
40 VC=unset 43 VC=unset
41fi 44fi
42test "$VN" = "$VC" || { 45test "$VN" = "$VC" || {
43 echo >&2 "PERF_VERSION = $VN" 46 echo >&2 " PERF_VERSION = $VN"
44 echo "#define PERF_VERSION \"$VN\"" >$GVF 47 echo "#define PERF_VERSION \"$VN\"" >$GVF
45} 48}
46 49
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 7eae5488ecea..cf6242c92ee2 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -825,20 +825,16 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
825 dl->ops.target.offset = dl->ops.target.addr - 825 dl->ops.target.offset = dl->ops.target.addr -
826 map__rip_2objdump(map, sym->start); 826 map__rip_2objdump(map, sym->start);
827 827
828 /* 828 /* kcore has no symbols, so add the call target name */
829 * kcore has no symbols, so add the call target name if it is on the
830 * same map.
831 */
832 if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) { 829 if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) {
833 struct symbol *s; 830 struct addr_map_symbol target = {
834 u64 ip = dl->ops.target.addr; 831 .map = map,
835 832 .addr = dl->ops.target.addr,
836 if (ip >= map->start && ip <= map->end) { 833 };
837 ip = map->map_ip(map, ip); 834
838 s = map__find_symbol(map, ip, NULL); 835 if (!map_groups__find_ams(&target, NULL) &&
839 if (s && s->start == ip) 836 target.sym->start == target.al_addr)
840 dl->ops.target.name = strdup(s->name); 837 dl->ops.target.name = strdup(target.sym->name);
841 }
842 } 838 }
843 839
844 disasm__add(&notes->src->source, dl); 840 disasm__add(&notes->src->source, dl);
@@ -879,6 +875,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
879 FILE *file; 875 FILE *file;
880 int err = 0; 876 int err = 0;
881 char symfs_filename[PATH_MAX]; 877 char symfs_filename[PATH_MAX];
878 struct kcore_extract kce;
879 bool delete_extract = false;
882 880
883 if (filename) { 881 if (filename) {
884 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", 882 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
@@ -940,6 +938,23 @@ fallback:
940 pr_debug("annotating [%p] %30s : [%p] %30s\n", 938 pr_debug("annotating [%p] %30s : [%p] %30s\n",
941 dso, dso->long_name, sym, sym->name); 939 dso, dso->long_name, sym, sym->name);
942 940
941 if (dso__is_kcore(dso)) {
942 kce.kcore_filename = symfs_filename;
943 kce.addr = map__rip_2objdump(map, sym->start);
944 kce.offs = sym->start;
945 kce.len = sym->end + 1 - sym->start;
946 if (!kcore_extract__create(&kce)) {
947 delete_extract = true;
948 strlcpy(symfs_filename, kce.extract_filename,
949 sizeof(symfs_filename));
950 if (free_filename) {
951 free(filename);
952 free_filename = false;
953 }
954 filename = symfs_filename;
955 }
956 }
957
943 snprintf(command, sizeof(command), 958 snprintf(command, sizeof(command),
944 "%s %s%s --start-address=0x%016" PRIx64 959 "%s %s%s --start-address=0x%016" PRIx64
945 " --stop-address=0x%016" PRIx64 960 " --stop-address=0x%016" PRIx64
@@ -972,6 +987,8 @@ fallback:
972 987
973 pclose(file); 988 pclose(file);
974out_free_filename: 989out_free_filename:
990 if (delete_extract)
991 kcore_extract__delete(&kce);
975 if (free_filename) 992 if (free_filename)
976 free(filename); 993 free(filename);
977 return err; 994 return err;
@@ -1070,7 +1087,7 @@ static void symbol__free_source_line(struct symbol *sym, int len)
1070 (sizeof(src_line->p) * (src_line->nr_pcnt - 1)); 1087 (sizeof(src_line->p) * (src_line->nr_pcnt - 1));
1071 1088
1072 for (i = 0; i < len; i++) { 1089 for (i = 0; i < len; i++) {
1073 free(src_line->path); 1090 free_srcline(src_line->path);
1074 src_line = (void *)src_line + sizeof_src_line; 1091 src_line = (void *)src_line + sizeof_src_line;
1075 } 1092 }
1076 1093
@@ -1081,13 +1098,11 @@ static void symbol__free_source_line(struct symbol *sym, int len)
1081/* Get the filename:line for the colored entries */ 1098/* Get the filename:line for the colored entries */
1082static int symbol__get_source_line(struct symbol *sym, struct map *map, 1099static int symbol__get_source_line(struct symbol *sym, struct map *map,
1083 struct perf_evsel *evsel, 1100 struct perf_evsel *evsel,
1084 struct rb_root *root, int len, 1101 struct rb_root *root, int len)
1085 const char *filename)
1086{ 1102{
1087 u64 start; 1103 u64 start;
1088 int i, k; 1104 int i, k;
1089 int evidx = evsel->idx; 1105 int evidx = evsel->idx;
1090 char cmd[PATH_MAX * 2];
1091 struct source_line *src_line; 1106 struct source_line *src_line;
1092 struct annotation *notes = symbol__annotation(sym); 1107 struct annotation *notes = symbol__annotation(sym);
1093 struct sym_hist *h = annotation__histogram(notes, evidx); 1108 struct sym_hist *h = annotation__histogram(notes, evidx);
@@ -1115,10 +1130,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
1115 start = map__rip_2objdump(map, sym->start); 1130 start = map__rip_2objdump(map, sym->start);
1116 1131
1117 for (i = 0; i < len; i++) { 1132 for (i = 0; i < len; i++) {
1118 char *path = NULL;
1119 size_t line_len;
1120 u64 offset; 1133 u64 offset;
1121 FILE *fp;
1122 double percent_max = 0.0; 1134 double percent_max = 0.0;
1123 1135
1124 src_line->nr_pcnt = nr_pcnt; 1136 src_line->nr_pcnt = nr_pcnt;
@@ -1135,23 +1147,9 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
1135 goto next; 1147 goto next;
1136 1148
1137 offset = start + i; 1149 offset = start + i;
1138 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); 1150 src_line->path = get_srcline(map->dso, offset);
1139 fp = popen(cmd, "r");
1140 if (!fp)
1141 goto next;
1142
1143 if (getline(&path, &line_len, fp) < 0 || !line_len)
1144 goto next_close;
1145
1146 src_line->path = malloc(sizeof(char) * line_len + 1);
1147 if (!src_line->path)
1148 goto next_close;
1149
1150 strcpy(src_line->path, path);
1151 insert_source_line(&tmp_root, src_line); 1151 insert_source_line(&tmp_root, src_line);
1152 1152
1153 next_close:
1154 pclose(fp);
1155 next: 1153 next:
1156 src_line = (void *)src_line + sizeof_src_line; 1154 src_line = (void *)src_line + sizeof_src_line;
1157 } 1155 }
@@ -1192,7 +1190,7 @@ static void print_summary(struct rb_root *root, const char *filename)
1192 1190
1193 path = src_line->path; 1191 path = src_line->path;
1194 color = get_percent_color(percent_max); 1192 color = get_percent_color(percent_max);
1195 color_fprintf(stdout, color, " %s", path); 1193 color_fprintf(stdout, color, " %s\n", path);
1196 1194
1197 node = rb_next(node); 1195 node = rb_next(node);
1198 } 1196 }
@@ -1356,7 +1354,6 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
1356 bool full_paths, int min_pcnt, int max_lines) 1354 bool full_paths, int min_pcnt, int max_lines)
1357{ 1355{
1358 struct dso *dso = map->dso; 1356 struct dso *dso = map->dso;
1359 const char *filename = dso->long_name;
1360 struct rb_root source_line = RB_ROOT; 1357 struct rb_root source_line = RB_ROOT;
1361 u64 len; 1358 u64 len;
1362 1359
@@ -1366,9 +1363,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
1366 len = symbol__size(sym); 1363 len = symbol__size(sym);
1367 1364
1368 if (print_lines) { 1365 if (print_lines) {
1369 symbol__get_source_line(sym, map, evsel, &source_line, 1366 symbol__get_source_line(sym, map, evsel, &source_line, len);
1370 len, filename); 1367 print_summary(&source_line, dso->long_name);
1371 print_summary(&source_line, filename);
1372 } 1368 }
1373 1369
1374 symbol__annotate_printf(sym, map, evsel, full_paths, 1370 symbol__annotate_printf(sym, map, evsel, full_paths,
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index af755156d278..834b7b57b788 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -150,7 +150,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
150 struct perf_evsel *evsel, bool print_lines, 150 struct perf_evsel *evsel, bool print_lines,
151 bool full_paths, int min_pcnt, int max_lines); 151 bool full_paths, int min_pcnt, int max_lines);
152 152
153#ifdef SLANG_SUPPORT 153#ifdef HAVE_SLANG_SUPPORT
154int symbol__tui_annotate(struct symbol *sym, struct map *map, 154int symbol__tui_annotate(struct symbol *sym, struct map *map,
155 struct perf_evsel *evsel, 155 struct perf_evsel *evsel,
156 struct hist_browser_timer *hbt); 156 struct hist_browser_timer *hbt);
@@ -165,30 +165,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused,
165} 165}
166#endif 166#endif
167 167
168#ifdef GTK2_SUPPORT
169int symbol__gtk_annotate(struct symbol *sym, struct map *map,
170 struct perf_evsel *evsel,
171 struct hist_browser_timer *hbt);
172
173static inline int hist_entry__gtk_annotate(struct hist_entry *he,
174 struct perf_evsel *evsel,
175 struct hist_browser_timer *hbt)
176{
177 return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt);
178}
179
180void perf_gtk__show_annotations(void);
181#else
182static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused,
183 struct perf_evsel *evsel __maybe_unused,
184 struct hist_browser_timer *hbt __maybe_unused)
185{
186 return 0;
187}
188
189static inline void perf_gtk__show_annotations(void) {}
190#endif
191
192extern const char *disassembler_style; 168extern const char *disassembler_style;
193 169
194#endif /* __PERF_ANNOTATE_H */ 170#endif /* __PERF_ANNOTATE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 7ded71d19d75..a92770c98cc7 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -89,14 +89,14 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
89 return raw - build_id; 89 return raw - build_id;
90} 90}
91 91
92char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 92char *dso__build_id_filename(struct dso *dso, char *bf, size_t size)
93{ 93{
94 char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 94 char build_id_hex[BUILD_ID_SIZE * 2 + 1];
95 95
96 if (!self->has_build_id) 96 if (!dso->has_build_id)
97 return NULL; 97 return NULL;
98 98
99 build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex); 99 build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex);
100 if (bf == NULL) { 100 if (bf == NULL) {
101 if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir, 101 if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
102 build_id_hex, build_id_hex + 2) < 0) 102 build_id_hex, build_id_hex + 2) < 0)
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index a811f5c62e18..929f28a7c14d 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -10,10 +10,9 @@ extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso; 10struct dso;
11 11
12int build_id__sprintf(const u8 *build_id, int len, char *bf); 12int build_id__sprintf(const u8 *build_id, int len, char *bf);
13char *dso__build_id_filename(struct dso *self, char *bf, size_t size); 13char *dso__build_id_filename(struct dso *dso, char *bf, size_t size);
14 14
15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, 15int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
16 struct perf_sample *sample, struct perf_evsel *evsel, 16 struct perf_sample *sample, struct perf_evsel *evsel,
17 struct machine *machine); 17 struct machine *machine);
18
19#endif 18#endif
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 26e367239873..7b176dd02e1a 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -70,8 +70,7 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
70extern char *perf_pathdup(const char *fmt, ...) 70extern char *perf_pathdup(const char *fmt, ...)
71 __attribute__((format (printf, 1, 2))); 71 __attribute__((format (printf, 1, 2)));
72 72
73#ifndef HAVE_STRLCPY 73/* Matches the libc/libbsd function attribute so we declare this unconditionally: */
74extern size_t strlcpy(char *dest, const char *src, size_t size); 74extern size_t strlcpy(char *dest, const char *src, size_t size);
75#endif
76 75
77#endif /* __PERF_CACHE_H */ 76#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 482f68081cd8..e3970e3eaacf 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -21,12 +21,6 @@
21 21
22__thread struct callchain_cursor callchain_cursor; 22__thread struct callchain_cursor callchain_cursor;
23 23
24#define chain_for_each_child(child, parent) \
25 list_for_each_entry(child, &parent->children, siblings)
26
27#define chain_for_each_child_safe(child, next, parent) \
28 list_for_each_entry_safe(child, next, &parent->children, siblings)
29
30static void 24static void
31rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 25rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
32 enum chain_mode mode) 26 enum chain_mode mode)
@@ -71,10 +65,16 @@ static void
71__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node, 65__sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
72 u64 min_hit) 66 u64 min_hit)
73{ 67{
68 struct rb_node *n;
74 struct callchain_node *child; 69 struct callchain_node *child;
75 70
76 chain_for_each_child(child, node) 71 n = rb_first(&node->rb_root_in);
72 while (n) {
73 child = rb_entry(n, struct callchain_node, rb_node_in);
74 n = rb_next(n);
75
77 __sort_chain_flat(rb_root, child, min_hit); 76 __sort_chain_flat(rb_root, child, min_hit);
77 }
78 78
79 if (node->hit && node->hit >= min_hit) 79 if (node->hit && node->hit >= min_hit)
80 rb_insert_callchain(rb_root, node, CHAIN_FLAT); 80 rb_insert_callchain(rb_root, node, CHAIN_FLAT);
@@ -94,11 +94,16 @@ sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
94static void __sort_chain_graph_abs(struct callchain_node *node, 94static void __sort_chain_graph_abs(struct callchain_node *node,
95 u64 min_hit) 95 u64 min_hit)
96{ 96{
97 struct rb_node *n;
97 struct callchain_node *child; 98 struct callchain_node *child;
98 99
99 node->rb_root = RB_ROOT; 100 node->rb_root = RB_ROOT;
101 n = rb_first(&node->rb_root_in);
102
103 while (n) {
104 child = rb_entry(n, struct callchain_node, rb_node_in);
105 n = rb_next(n);
100 106
101 chain_for_each_child(child, node) {
102 __sort_chain_graph_abs(child, min_hit); 107 __sort_chain_graph_abs(child, min_hit);
103 if (callchain_cumul_hits(child) >= min_hit) 108 if (callchain_cumul_hits(child) >= min_hit)
104 rb_insert_callchain(&node->rb_root, child, 109 rb_insert_callchain(&node->rb_root, child,
@@ -117,13 +122,18 @@ sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
117static void __sort_chain_graph_rel(struct callchain_node *node, 122static void __sort_chain_graph_rel(struct callchain_node *node,
118 double min_percent) 123 double min_percent)
119{ 124{
125 struct rb_node *n;
120 struct callchain_node *child; 126 struct callchain_node *child;
121 u64 min_hit; 127 u64 min_hit;
122 128
123 node->rb_root = RB_ROOT; 129 node->rb_root = RB_ROOT;
124 min_hit = ceil(node->children_hit * min_percent); 130 min_hit = ceil(node->children_hit * min_percent);
125 131
126 chain_for_each_child(child, node) { 132 n = rb_first(&node->rb_root_in);
133 while (n) {
134 child = rb_entry(n, struct callchain_node, rb_node_in);
135 n = rb_next(n);
136
127 __sort_chain_graph_rel(child, min_percent); 137 __sort_chain_graph_rel(child, min_percent);
128 if (callchain_cumul_hits(child) >= min_hit) 138 if (callchain_cumul_hits(child) >= min_hit)
129 rb_insert_callchain(&node->rb_root, child, 139 rb_insert_callchain(&node->rb_root, child,
@@ -173,19 +183,26 @@ create_child(struct callchain_node *parent, bool inherit_children)
173 return NULL; 183 return NULL;
174 } 184 }
175 new->parent = parent; 185 new->parent = parent;
176 INIT_LIST_HEAD(&new->children);
177 INIT_LIST_HEAD(&new->val); 186 INIT_LIST_HEAD(&new->val);
178 187
179 if (inherit_children) { 188 if (inherit_children) {
180 struct callchain_node *next; 189 struct rb_node *n;
190 struct callchain_node *child;
191
192 new->rb_root_in = parent->rb_root_in;
193 parent->rb_root_in = RB_ROOT;
181 194
182 list_splice(&parent->children, &new->children); 195 n = rb_first(&new->rb_root_in);
183 INIT_LIST_HEAD(&parent->children); 196 while (n) {
197 child = rb_entry(n, struct callchain_node, rb_node_in);
198 child->parent = new;
199 n = rb_next(n);
200 }
184 201
185 chain_for_each_child(next, new) 202 /* make it the first child */
186 next->parent = new; 203 rb_link_node(&new->rb_node_in, NULL, &parent->rb_root_in.rb_node);
204 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
187 } 205 }
188 list_add_tail(&new->siblings, &parent->children);
189 206
190 return new; 207 return new;
191} 208}
@@ -223,7 +240,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
223 } 240 }
224} 241}
225 242
226static void 243static struct callchain_node *
227add_child(struct callchain_node *parent, 244add_child(struct callchain_node *parent,
228 struct callchain_cursor *cursor, 245 struct callchain_cursor *cursor,
229 u64 period) 246 u64 period)
@@ -235,6 +252,19 @@ add_child(struct callchain_node *parent,
235 252
236 new->children_hit = 0; 253 new->children_hit = 0;
237 new->hit = period; 254 new->hit = period;
255 return new;
256}
257
258static s64 match_chain(struct callchain_cursor_node *node,
259 struct callchain_list *cnode)
260{
261 struct symbol *sym = node->sym;
262
263 if (cnode->ms.sym && sym &&
264 callchain_param.key == CCKEY_FUNCTION)
265 return cnode->ms.sym->start - sym->start;
266 else
267 return cnode->ip - node->ip;
238} 268}
239 269
240/* 270/*
@@ -272,9 +302,33 @@ split_add_child(struct callchain_node *parent,
272 302
273 /* create a new child for the new branch if any */ 303 /* create a new child for the new branch if any */
274 if (idx_total < cursor->nr) { 304 if (idx_total < cursor->nr) {
305 struct callchain_node *first;
306 struct callchain_list *cnode;
307 struct callchain_cursor_node *node;
308 struct rb_node *p, **pp;
309
275 parent->hit = 0; 310 parent->hit = 0;
276 add_child(parent, cursor, period);
277 parent->children_hit += period; 311 parent->children_hit += period;
312
313 node = callchain_cursor_current(cursor);
314 new = add_child(parent, cursor, period);
315
316 /*
317 * This is second child since we moved parent's children
318 * to new (first) child above.
319 */
320 p = parent->rb_root_in.rb_node;
321 first = rb_entry(p, struct callchain_node, rb_node_in);
322 cnode = list_first_entry(&first->val, struct callchain_list,
323 list);
324
325 if (match_chain(node, cnode) < 0)
326 pp = &p->rb_left;
327 else
328 pp = &p->rb_right;
329
330 rb_link_node(&new->rb_node_in, p, pp);
331 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
278 } else { 332 } else {
279 parent->hit = period; 333 parent->hit = period;
280 } 334 }
@@ -291,16 +345,40 @@ append_chain_children(struct callchain_node *root,
291 u64 period) 345 u64 period)
292{ 346{
293 struct callchain_node *rnode; 347 struct callchain_node *rnode;
348 struct callchain_cursor_node *node;
349 struct rb_node **p = &root->rb_root_in.rb_node;
350 struct rb_node *parent = NULL;
351
352 node = callchain_cursor_current(cursor);
353 if (!node)
354 return;
294 355
295 /* lookup in childrens */ 356 /* lookup in childrens */
296 chain_for_each_child(rnode, root) { 357 while (*p) {
297 unsigned int ret = append_chain(rnode, cursor, period); 358 s64 ret;
359 struct callchain_list *cnode;
298 360
299 if (!ret) 361 parent = *p;
362 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
363 cnode = list_first_entry(&rnode->val, struct callchain_list,
364 list);
365
366 /* just check first entry */
367 ret = match_chain(node, cnode);
368 if (ret == 0) {
369 append_chain(rnode, cursor, period);
300 goto inc_children_hit; 370 goto inc_children_hit;
371 }
372
373 if (ret < 0)
374 p = &parent->rb_left;
375 else
376 p = &parent->rb_right;
301 } 377 }
302 /* nothing in children, add to the current node */ 378 /* nothing in children, add to the current node */
303 add_child(root, cursor, period); 379 rnode = add_child(root, cursor, period);
380 rb_link_node(&rnode->rb_node_in, parent, p);
381 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
304 382
305inc_children_hit: 383inc_children_hit:
306 root->children_hit += period; 384 root->children_hit += period;
@@ -325,28 +403,20 @@ append_chain(struct callchain_node *root,
325 */ 403 */
326 list_for_each_entry(cnode, &root->val, list) { 404 list_for_each_entry(cnode, &root->val, list) {
327 struct callchain_cursor_node *node; 405 struct callchain_cursor_node *node;
328 struct symbol *sym;
329 406
330 node = callchain_cursor_current(cursor); 407 node = callchain_cursor_current(cursor);
331 if (!node) 408 if (!node)
332 break; 409 break;
333 410
334 sym = node->sym; 411 if (match_chain(node, cnode) != 0)
335
336 if (cnode->ms.sym && sym &&
337 callchain_param.key == CCKEY_FUNCTION) {
338 if (cnode->ms.sym->start != sym->start)
339 break;
340 } else if (cnode->ip != node->ip)
341 break; 412 break;
342 413
343 if (!found) 414 found = true;
344 found = true;
345 415
346 callchain_cursor_advance(cursor); 416 callchain_cursor_advance(cursor);
347 } 417 }
348 418
349 /* matches not, relay on the parent */ 419 /* matches not, relay no the parent */
350 if (!found) { 420 if (!found) {
351 cursor->curr = curr_snap; 421 cursor->curr = curr_snap;
352 cursor->pos = start; 422 cursor->pos = start;
@@ -395,8 +465,9 @@ merge_chain_branch(struct callchain_cursor *cursor,
395 struct callchain_node *dst, struct callchain_node *src) 465 struct callchain_node *dst, struct callchain_node *src)
396{ 466{
397 struct callchain_cursor_node **old_last = cursor->last; 467 struct callchain_cursor_node **old_last = cursor->last;
398 struct callchain_node *child, *next_child; 468 struct callchain_node *child;
399 struct callchain_list *list, *next_list; 469 struct callchain_list *list, *next_list;
470 struct rb_node *n;
400 int old_pos = cursor->nr; 471 int old_pos = cursor->nr;
401 int err = 0; 472 int err = 0;
402 473
@@ -412,12 +483,16 @@ merge_chain_branch(struct callchain_cursor *cursor,
412 append_chain_children(dst, cursor, src->hit); 483 append_chain_children(dst, cursor, src->hit);
413 } 484 }
414 485
415 chain_for_each_child_safe(child, next_child, src) { 486 n = rb_first(&src->rb_root_in);
487 while (n) {
488 child = container_of(n, struct callchain_node, rb_node_in);
489 n = rb_next(n);
490 rb_erase(&child->rb_node_in, &src->rb_root_in);
491
416 err = merge_chain_branch(cursor, dst, child); 492 err = merge_chain_branch(cursor, dst, child);
417 if (err) 493 if (err)
418 break; 494 break;
419 495
420 list_del(&child->siblings);
421 free(child); 496 free(child);
422 } 497 }
423 498
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 2b585bc308cf..4f7f989876ec 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -21,11 +21,11 @@ enum chain_order {
21 21
22struct callchain_node { 22struct callchain_node {
23 struct callchain_node *parent; 23 struct callchain_node *parent;
24 struct list_head siblings;
25 struct list_head children;
26 struct list_head val; 24 struct list_head val;
27 struct rb_node rb_node; /* to sort nodes in an rbtree */ 25 struct rb_node rb_node_in; /* to insert nodes in an rbtree */
28 struct rb_root rb_root; /* sorted tree of children */ 26 struct rb_node rb_node; /* to sort nodes in an output tree */
27 struct rb_root rb_root_in; /* input tree of children */
28 struct rb_root rb_root; /* sorted output tree of children */
29 unsigned int val_nr; 29 unsigned int val_nr;
30 u64 hit; 30 u64 hit;
31 u64 children_hit; 31 u64 children_hit;
@@ -86,13 +86,12 @@ extern __thread struct callchain_cursor callchain_cursor;
86 86
87static inline void callchain_init(struct callchain_root *root) 87static inline void callchain_init(struct callchain_root *root)
88{ 88{
89 INIT_LIST_HEAD(&root->node.siblings);
90 INIT_LIST_HEAD(&root->node.children);
91 INIT_LIST_HEAD(&root->node.val); 89 INIT_LIST_HEAD(&root->node.val);
92 90
93 root->node.parent = NULL; 91 root->node.parent = NULL;
94 root->node.hit = 0; 92 root->node.hit = 0;
95 root->node.children_hit = 0; 93 root->node.children_hit = 0;
94 root->node.rb_root_in = RB_ROOT;
96 root->max_depth = 0; 95 root->max_depth = 0;
97} 96}
98 97
@@ -147,6 +146,9 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor)
147 146
148struct option; 147struct option;
149 148
149int record_parse_callchain(const char *arg, struct perf_record_opts *opts);
150int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); 150int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset);
151int record_callchain_opt(const struct option *opt, const char *arg, int unset);
152
151extern const char record_callchain_help[]; 153extern const char record_callchain_help[];
152#endif /* __PERF_CALLCHAIN_H */ 154#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 11e46da17bbb..66e44a5019d5 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -318,8 +318,15 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
318 return r; 318 return r;
319} 319}
320 320
321int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent) 321int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
322{ 322{
323 const char *color = get_percent_color(percent); 323 va_list args;
324 double percent;
325 const char *color;
326
327 va_start(args, fmt);
328 percent = va_arg(args, double);
329 va_end(args);
330 color = get_percent_color(percent);
324 return color_snprintf(bf, size, color, fmt, percent); 331 return color_snprintf(bf, size, color, fmt, percent);
325} 332}
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index dea082b79602..fced3840e99c 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -39,7 +39,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); 39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
42int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent); 42int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
43int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 43int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
44const char *get_percent_color(double percent); 44const char *get_percent_color(double percent);
45 45
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c
new file mode 100644
index 000000000000..ee0df0e24cdb
--- /dev/null
+++ b/tools/perf/util/comm.c
@@ -0,0 +1,121 @@
1#include "comm.h"
2#include "util.h"
3#include <stdlib.h>
4#include <stdio.h>
5
6struct comm_str {
7 char *str;
8 struct rb_node rb_node;
9 int ref;
10};
11
12/* Should perhaps be moved to struct machine */
13static struct rb_root comm_str_root;
14
15static void comm_str__get(struct comm_str *cs)
16{
17 cs->ref++;
18}
19
20static void comm_str__put(struct comm_str *cs)
21{
22 if (!--cs->ref) {
23 rb_erase(&cs->rb_node, &comm_str_root);
24 free(cs->str);
25 free(cs);
26 }
27}
28
29static struct comm_str *comm_str__alloc(const char *str)
30{
31 struct comm_str *cs;
32
33 cs = zalloc(sizeof(*cs));
34 if (!cs)
35 return NULL;
36
37 cs->str = strdup(str);
38 if (!cs->str) {
39 free(cs);
40 return NULL;
41 }
42
43 return cs;
44}
45
46static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root)
47{
48 struct rb_node **p = &root->rb_node;
49 struct rb_node *parent = NULL;
50 struct comm_str *iter, *new;
51 int cmp;
52
53 while (*p != NULL) {
54 parent = *p;
55 iter = rb_entry(parent, struct comm_str, rb_node);
56
57 cmp = strcmp(str, iter->str);
58 if (!cmp)
59 return iter;
60
61 if (cmp < 0)
62 p = &(*p)->rb_left;
63 else
64 p = &(*p)->rb_right;
65 }
66
67 new = comm_str__alloc(str);
68 if (!new)
69 return NULL;
70
71 rb_link_node(&new->rb_node, parent, p);
72 rb_insert_color(&new->rb_node, root);
73
74 return new;
75}
76
77struct comm *comm__new(const char *str, u64 timestamp)
78{
79 struct comm *comm = zalloc(sizeof(*comm));
80
81 if (!comm)
82 return NULL;
83
84 comm->start = timestamp;
85
86 comm->comm_str = comm_str__findnew(str, &comm_str_root);
87 if (!comm->comm_str) {
88 free(comm);
89 return NULL;
90 }
91
92 comm_str__get(comm->comm_str);
93
94 return comm;
95}
96
97void comm__override(struct comm *comm, const char *str, u64 timestamp)
98{
99 struct comm_str *old = comm->comm_str;
100
101 comm->comm_str = comm_str__findnew(str, &comm_str_root);
102 if (!comm->comm_str) {
103 comm->comm_str = old;
104 return;
105 }
106
107 comm->start = timestamp;
108 comm_str__get(comm->comm_str);
109 comm_str__put(old);
110}
111
112void comm__free(struct comm *comm)
113{
114 comm_str__put(comm->comm_str);
115 free(comm);
116}
117
118const char *comm__str(const struct comm *comm)
119{
120 return comm->comm_str->str;
121}
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h
new file mode 100644
index 000000000000..7a86e5656710
--- /dev/null
+++ b/tools/perf/util/comm.h
@@ -0,0 +1,21 @@
1#ifndef __PERF_COMM_H
2#define __PERF_COMM_H
3
4#include "../perf.h"
5#include <linux/rbtree.h>
6#include <linux/list.h>
7
8struct comm_str;
9
10struct comm {
11 struct comm_str *comm_str;
12 u64 start;
13 struct list_head list;
14};
15
16void comm__free(struct comm *comm);
17struct comm *comm__new(const char *str, u64 timestamp);
18const char *comm__str(const struct comm *comm);
19void comm__override(struct comm *comm, const char *str, u64 timestamp);
20
21#endif /* __PERF_COMM_H */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index beb8cf9f9976..a9b48c42e81e 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -1,5 +1,5 @@
1#include "util.h" 1#include "util.h"
2#include "sysfs.h" 2#include "fs.h"
3#include "../perf.h" 3#include "../perf.h"
4#include "cpumap.h" 4#include "cpumap.h"
5#include <assert.h> 5#include <assert.h>
@@ -216,7 +216,7 @@ int cpu_map__get_socket(struct cpu_map *map, int idx)
216 216
217 cpu = map->map[idx]; 217 cpu = map->map[idx];
218 218
219 mnt = sysfs_find_mountpoint(); 219 mnt = sysfs__mountpoint();
220 if (!mnt) 220 if (!mnt)
221 return -1; 221 return -1;
222 222
@@ -279,7 +279,7 @@ int cpu_map__get_core(struct cpu_map *map, int idx)
279 279
280 cpu = map->map[idx]; 280 cpu = map->map[idx];
281 281
282 mnt = sysfs_find_mountpoint(); 282 mnt = sysfs__mountpoint();
283 if (!mnt) 283 if (!mnt)
284 return -1; 284 return -1;
285 285
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
new file mode 100644
index 000000000000..7d09faf85cf1
--- /dev/null
+++ b/tools/perf/util/data.c
@@ -0,0 +1,120 @@
1#include <linux/compiler.h>
2#include <linux/kernel.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <unistd.h>
6#include <string.h>
7
8#include "data.h"
9#include "util.h"
10
11static bool check_pipe(struct perf_data_file *file)
12{
13 struct stat st;
14 bool is_pipe = false;
15 int fd = perf_data_file__is_read(file) ?
16 STDIN_FILENO : STDOUT_FILENO;
17
18 if (!file->path) {
19 if (!fstat(fd, &st) && S_ISFIFO(st.st_mode))
20 is_pipe = true;
21 } else {
22 if (!strcmp(file->path, "-"))
23 is_pipe = true;
24 }
25
26 if (is_pipe)
27 file->fd = fd;
28
29 return file->is_pipe = is_pipe;
30}
31
32static int check_backup(struct perf_data_file *file)
33{
34 struct stat st;
35
36 if (!stat(file->path, &st) && st.st_size) {
37 /* TODO check errors properly */
38 char oldname[PATH_MAX];
39 snprintf(oldname, sizeof(oldname), "%s.old",
40 file->path);
41 unlink(oldname);
42 rename(file->path, oldname);
43 }
44
45 return 0;
46}
47
48static int open_file_read(struct perf_data_file *file)
49{
50 struct stat st;
51 int fd;
52
53 fd = open(file->path, O_RDONLY);
54 if (fd < 0) {
55 int err = errno;
56
57 pr_err("failed to open %s: %s", file->path, strerror(err));
58 if (err == ENOENT && !strcmp(file->path, "perf.data"))
59 pr_err(" (try 'perf record' first)");
60 pr_err("\n");
61 return -err;
62 }
63
64 if (fstat(fd, &st) < 0)
65 goto out_close;
66
67 if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
68 pr_err("file %s not owned by current user or root\n",
69 file->path);
70 goto out_close;
71 }
72
73 if (!st.st_size) {
74 pr_info("zero-sized file (%s), nothing to do!\n",
75 file->path);
76 goto out_close;
77 }
78
79 file->size = st.st_size;
80 return fd;
81
82 out_close:
83 close(fd);
84 return -1;
85}
86
87static int open_file_write(struct perf_data_file *file)
88{
89 if (check_backup(file))
90 return -1;
91
92 return open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
93}
94
95static int open_file(struct perf_data_file *file)
96{
97 int fd;
98
99 fd = perf_data_file__is_read(file) ?
100 open_file_read(file) : open_file_write(file);
101
102 file->fd = fd;
103 return fd < 0 ? -1 : 0;
104}
105
106int perf_data_file__open(struct perf_data_file *file)
107{
108 if (check_pipe(file))
109 return 0;
110
111 if (!file->path)
112 file->path = "perf.data";
113
114 return open_file(file);
115}
116
117void perf_data_file__close(struct perf_data_file *file)
118{
119 close(file->fd);
120}
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h
new file mode 100644
index 000000000000..8c2df80152a5
--- /dev/null
+++ b/tools/perf/util/data.h
@@ -0,0 +1,48 @@
1#ifndef __PERF_DATA_H
2#define __PERF_DATA_H
3
4#include <stdbool.h>
5
6enum perf_data_mode {
7 PERF_DATA_MODE_WRITE,
8 PERF_DATA_MODE_READ,
9};
10
11struct perf_data_file {
12 const char *path;
13 int fd;
14 bool is_pipe;
15 bool force;
16 unsigned long size;
17 enum perf_data_mode mode;
18};
19
20static inline bool perf_data_file__is_read(struct perf_data_file *file)
21{
22 return file->mode == PERF_DATA_MODE_READ;
23}
24
25static inline bool perf_data_file__is_write(struct perf_data_file *file)
26{
27 return file->mode == PERF_DATA_MODE_WRITE;
28}
29
30static inline int perf_data_file__is_pipe(struct perf_data_file *file)
31{
32 return file->is_pipe;
33}
34
35static inline int perf_data_file__fd(struct perf_data_file *file)
36{
37 return file->fd;
38}
39
40static inline unsigned long perf_data_file__size(struct perf_data_file *file)
41{
42 return file->size;
43}
44
45int perf_data_file__open(struct perf_data_file *file);
46void perf_data_file__close(struct perf_data_file *file);
47
48#endif /* __PERF_DATA_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index e3c1ff8512c8..af4c687cc49b 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -7,19 +7,20 @@
7char dso__symtab_origin(const struct dso *dso) 7char dso__symtab_origin(const struct dso *dso)
8{ 8{
9 static const char origin[] = { 9 static const char origin[] = {
10 [DSO_BINARY_TYPE__KALLSYMS] = 'k', 10 [DSO_BINARY_TYPE__KALLSYMS] = 'k',
11 [DSO_BINARY_TYPE__VMLINUX] = 'v', 11 [DSO_BINARY_TYPE__VMLINUX] = 'v',
12 [DSO_BINARY_TYPE__JAVA_JIT] = 'j', 12 [DSO_BINARY_TYPE__JAVA_JIT] = 'j',
13 [DSO_BINARY_TYPE__DEBUGLINK] = 'l', 13 [DSO_BINARY_TYPE__DEBUGLINK] = 'l',
14 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', 14 [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B',
15 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', 15 [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
16 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', 16 [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
17 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', 17 [DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO] = 'o',
18 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', 18 [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
19 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', 19 [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
20 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', 20 [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
21 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', 21 [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
22 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', 22 [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
23 [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
23 }; 24 };
24 25
25 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) 26 if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
@@ -64,6 +65,28 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type,
64 symbol_conf.symfs, dso->long_name); 65 symbol_conf.symfs, dso->long_name);
65 break; 66 break;
66 67
68 case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
69 {
70 char *last_slash;
71 size_t len;
72 size_t dir_size;
73
74 last_slash = dso->long_name + dso->long_name_len;
75 while (last_slash != dso->long_name && *last_slash != '/')
76 last_slash--;
77
78 len = scnprintf(file, size, "%s", symbol_conf.symfs);
79 dir_size = last_slash - dso->long_name + 2;
80 if (dir_size > (size - len)) {
81 ret = -1;
82 break;
83 }
84 len += scnprintf(file + len, dir_size, "%s", dso->long_name);
85 len += scnprintf(file + len , size - len, ".debug%s",
86 last_slash);
87 break;
88 }
89
67 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 90 case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
68 if (!dso->has_build_id) { 91 if (!dso->has_build_id) {
69 ret = -1; 92 ret = -1;
@@ -427,6 +450,7 @@ struct dso *dso__new(const char *name)
427 dso->rel = 0; 450 dso->rel = 0;
428 dso->sorted_by_name = 0; 451 dso->sorted_by_name = 0;
429 dso->has_build_id = 0; 452 dso->has_build_id = 0;
453 dso->has_srcline = 1;
430 dso->kernel = DSO_TYPE_USER; 454 dso->kernel = DSO_TYPE_USER;
431 dso->needs_swap = DSO_SWAP__UNSET; 455 dso->needs_swap = DSO_SWAP__UNSET;
432 INIT_LIST_HEAD(&dso->node); 456 INIT_LIST_HEAD(&dso->node);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index b793053335d6..9ac666abbe7e 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -6,6 +6,7 @@
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include "types.h"
8#include "map.h" 8#include "map.h"
9#include "build-id.h"
9 10
10enum dso_binary_type { 11enum dso_binary_type {
11 DSO_BINARY_TYPE__KALLSYMS = 0, 12 DSO_BINARY_TYPE__KALLSYMS = 0,
@@ -23,6 +24,7 @@ enum dso_binary_type {
23 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 24 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
24 DSO_BINARY_TYPE__KCORE, 25 DSO_BINARY_TYPE__KCORE,
25 DSO_BINARY_TYPE__GUEST_KCORE, 26 DSO_BINARY_TYPE__GUEST_KCORE,
27 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
26 DSO_BINARY_TYPE__NOT_FOUND, 28 DSO_BINARY_TYPE__NOT_FOUND,
27}; 29};
28 30
@@ -81,6 +83,7 @@ struct dso {
81 enum dso_binary_type data_type; 83 enum dso_binary_type data_type;
82 u8 adjust_symbols:1; 84 u8 adjust_symbols:1;
83 u8 has_build_id:1; 85 u8 has_build_id:1;
86 u8 has_srcline:1;
84 u8 hit:1; 87 u8 hit:1;
85 u8 annotate_warned:1; 88 u8 annotate_warned:1;
86 u8 sname_alloc:1; 89 u8 sname_alloc:1;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 9b393e7dca6f..bb788c109fe6 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -170,7 +170,8 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
170 union perf_event *event, 170 union perf_event *event,
171 pid_t pid, pid_t tgid, 171 pid_t pid, pid_t tgid,
172 perf_event__handler_t process, 172 perf_event__handler_t process,
173 struct machine *machine) 173 struct machine *machine,
174 bool mmap_data)
174{ 175{
175 char filename[PATH_MAX]; 176 char filename[PATH_MAX];
176 FILE *fp; 177 FILE *fp;
@@ -187,18 +188,13 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
187 return -1; 188 return -1;
188 } 189 }
189 190
190 event->header.type = PERF_RECORD_MMAP2; 191 event->header.type = PERF_RECORD_MMAP;
191 /*
192 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
193 */
194 event->header.misc = PERF_RECORD_MISC_USER;
195 192
196 while (1) { 193 while (1) {
197 char bf[BUFSIZ]; 194 char bf[BUFSIZ];
198 char prot[5]; 195 char prot[5];
199 char execname[PATH_MAX]; 196 char execname[PATH_MAX];
200 char anonstr[] = "//anon"; 197 char anonstr[] = "//anon";
201 unsigned int ino;
202 size_t size; 198 size_t size;
203 ssize_t n; 199 ssize_t n;
204 200
@@ -209,33 +205,40 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
209 strcpy(execname, ""); 205 strcpy(execname, "");
210 206
211 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 207 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
212 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", 208 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
213 &event->mmap2.start, &event->mmap2.len, prot, 209 &event->mmap.start, &event->mmap.len, prot,
214 &event->mmap2.pgoff, &event->mmap2.maj, 210 &event->mmap.pgoff,
215 &event->mmap2.min, 211 execname);
216 &ino, execname); 212 /*
217 213 * Anon maps don't have the execname.
218 event->mmap2.ino = (u64)ino; 214 */
219 215 if (n < 4)
220 if (n != 8)
221 continue; 216 continue;
217 /*
218 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
219 */
220 event->header.misc = PERF_RECORD_MISC_USER;
222 221
223 if (prot[2] != 'x') 222 if (prot[2] != 'x') {
224 continue; 223 if (!mmap_data || prot[0] != 'r')
224 continue;
225
226 event->header.misc |= PERF_RECORD_MISC_MMAP_DATA;
227 }
225 228
226 if (!strcmp(execname, "")) 229 if (!strcmp(execname, ""))
227 strcpy(execname, anonstr); 230 strcpy(execname, anonstr);
228 231
229 size = strlen(execname) + 1; 232 size = strlen(execname) + 1;
230 memcpy(event->mmap2.filename, execname, size); 233 memcpy(event->mmap.filename, execname, size);
231 size = PERF_ALIGN(size, sizeof(u64)); 234 size = PERF_ALIGN(size, sizeof(u64));
232 event->mmap2.len -= event->mmap.start; 235 event->mmap.len -= event->mmap.start;
233 event->mmap2.header.size = (sizeof(event->mmap2) - 236 event->mmap.header.size = (sizeof(event->mmap) -
234 (sizeof(event->mmap2.filename) - size)); 237 (sizeof(event->mmap.filename) - size));
235 memset(event->mmap2.filename + size, 0, machine->id_hdr_size); 238 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
236 event->mmap2.header.size += machine->id_hdr_size; 239 event->mmap.header.size += machine->id_hdr_size;
237 event->mmap2.pid = tgid; 240 event->mmap.pid = tgid;
238 event->mmap2.tid = pid; 241 event->mmap.tid = pid;
239 242
240 if (process(tool, event, &synth_sample, machine) != 0) { 243 if (process(tool, event, &synth_sample, machine) != 0) {
241 rc = -1; 244 rc = -1;
@@ -308,20 +311,21 @@ static int __event__synthesize_thread(union perf_event *comm_event,
308 pid_t pid, int full, 311 pid_t pid, int full,
309 perf_event__handler_t process, 312 perf_event__handler_t process,
310 struct perf_tool *tool, 313 struct perf_tool *tool,
311 struct machine *machine) 314 struct machine *machine, bool mmap_data)
312{ 315{
313 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full, 316 pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full,
314 process, machine); 317 process, machine);
315 if (tgid == -1) 318 if (tgid == -1)
316 return -1; 319 return -1;
317 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 320 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
318 process, machine); 321 process, machine, mmap_data);
319} 322}
320 323
321int perf_event__synthesize_thread_map(struct perf_tool *tool, 324int perf_event__synthesize_thread_map(struct perf_tool *tool,
322 struct thread_map *threads, 325 struct thread_map *threads,
323 perf_event__handler_t process, 326 perf_event__handler_t process,
324 struct machine *machine) 327 struct machine *machine,
328 bool mmap_data)
325{ 329{
326 union perf_event *comm_event, *mmap_event; 330 union perf_event *comm_event, *mmap_event;
327 int err = -1, thread, j; 331 int err = -1, thread, j;
@@ -338,7 +342,8 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
338 for (thread = 0; thread < threads->nr; ++thread) { 342 for (thread = 0; thread < threads->nr; ++thread) {
339 if (__event__synthesize_thread(comm_event, mmap_event, 343 if (__event__synthesize_thread(comm_event, mmap_event,
340 threads->map[thread], 0, 344 threads->map[thread], 0,
341 process, tool, machine)) { 345 process, tool, machine,
346 mmap_data)) {
342 err = -1; 347 err = -1;
343 break; 348 break;
344 } 349 }
@@ -360,10 +365,10 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
360 365
361 /* if not, generate events for it */ 366 /* if not, generate events for it */
362 if (need_leader && 367 if (need_leader &&
363 __event__synthesize_thread(comm_event, 368 __event__synthesize_thread(comm_event, mmap_event,
364 mmap_event, 369 comm_event->comm.pid, 0,
365 comm_event->comm.pid, 0, 370 process, tool, machine,
366 process, tool, machine)) { 371 mmap_data)) {
367 err = -1; 372 err = -1;
368 break; 373 break;
369 } 374 }
@@ -378,7 +383,7 @@ out:
378 383
379int perf_event__synthesize_threads(struct perf_tool *tool, 384int perf_event__synthesize_threads(struct perf_tool *tool,
380 perf_event__handler_t process, 385 perf_event__handler_t process,
381 struct machine *machine) 386 struct machine *machine, bool mmap_data)
382{ 387{
383 DIR *proc; 388 DIR *proc;
384 struct dirent dirent, *next; 389 struct dirent dirent, *next;
@@ -408,7 +413,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
408 * one thread couldn't be synthesized. 413 * one thread couldn't be synthesized.
409 */ 414 */
410 __event__synthesize_thread(comm_event, mmap_event, pid, 1, 415 __event__synthesize_thread(comm_event, mmap_event, pid, 1,
411 process, tool, machine); 416 process, tool, machine, mmap_data);
412 } 417 }
413 418
414 err = 0; 419 err = 0;
@@ -516,52 +521,55 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
516 521
517int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 522int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
518 union perf_event *event, 523 union perf_event *event,
519 struct perf_sample *sample __maybe_unused, 524 struct perf_sample *sample,
520 struct machine *machine) 525 struct machine *machine)
521{ 526{
522 return machine__process_comm_event(machine, event); 527 return machine__process_comm_event(machine, event, sample);
523} 528}
524 529
525int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 530int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
526 union perf_event *event, 531 union perf_event *event,
527 struct perf_sample *sample __maybe_unused, 532 struct perf_sample *sample,
528 struct machine *machine) 533 struct machine *machine)
529{ 534{
530 return machine__process_lost_event(machine, event); 535 return machine__process_lost_event(machine, event, sample);
531} 536}
532 537
533size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 538size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
534{ 539{
535 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", 540 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n",
536 event->mmap.pid, event->mmap.tid, event->mmap.start, 541 event->mmap.pid, event->mmap.tid, event->mmap.start,
537 event->mmap.len, event->mmap.pgoff, event->mmap.filename); 542 event->mmap.len, event->mmap.pgoff,
543 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x',
544 event->mmap.filename);
538} 545}
539 546
540size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) 547size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
541{ 548{
542 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 549 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
543 " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n", 550 " %02x:%02x %"PRIu64" %"PRIu64"]: %c %s\n",
544 event->mmap2.pid, event->mmap2.tid, event->mmap2.start, 551 event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
545 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, 552 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
546 event->mmap2.min, event->mmap2.ino, 553 event->mmap2.min, event->mmap2.ino,
547 event->mmap2.ino_generation, 554 event->mmap2.ino_generation,
555 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x',
548 event->mmap2.filename); 556 event->mmap2.filename);
549} 557}
550 558
551int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 559int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
552 union perf_event *event, 560 union perf_event *event,
553 struct perf_sample *sample __maybe_unused, 561 struct perf_sample *sample,
554 struct machine *machine) 562 struct machine *machine)
555{ 563{
556 return machine__process_mmap_event(machine, event); 564 return machine__process_mmap_event(machine, event, sample);
557} 565}
558 566
559int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, 567int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
560 union perf_event *event, 568 union perf_event *event,
561 struct perf_sample *sample __maybe_unused, 569 struct perf_sample *sample,
562 struct machine *machine) 570 struct machine *machine)
563{ 571{
564 return machine__process_mmap2_event(machine, event); 572 return machine__process_mmap2_event(machine, event, sample);
565} 573}
566 574
567size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 575size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
@@ -573,18 +581,18 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
573 581
574int perf_event__process_fork(struct perf_tool *tool __maybe_unused, 582int perf_event__process_fork(struct perf_tool *tool __maybe_unused,
575 union perf_event *event, 583 union perf_event *event,
576 struct perf_sample *sample __maybe_unused, 584 struct perf_sample *sample,
577 struct machine *machine) 585 struct machine *machine)
578{ 586{
579 return machine__process_fork_event(machine, event); 587 return machine__process_fork_event(machine, event, sample);
580} 588}
581 589
582int perf_event__process_exit(struct perf_tool *tool __maybe_unused, 590int perf_event__process_exit(struct perf_tool *tool __maybe_unused,
583 union perf_event *event, 591 union perf_event *event,
584 struct perf_sample *sample __maybe_unused, 592 struct perf_sample *sample,
585 struct machine *machine) 593 struct machine *machine)
586{ 594{
587 return machine__process_exit_event(machine, event); 595 return machine__process_exit_event(machine, event, sample);
588} 596}
589 597
590size_t perf_event__fprintf(union perf_event *event, FILE *fp) 598size_t perf_event__fprintf(union perf_event *event, FILE *fp)
@@ -615,21 +623,21 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
615 623
616int perf_event__process(struct perf_tool *tool __maybe_unused, 624int perf_event__process(struct perf_tool *tool __maybe_unused,
617 union perf_event *event, 625 union perf_event *event,
618 struct perf_sample *sample __maybe_unused, 626 struct perf_sample *sample,
619 struct machine *machine) 627 struct machine *machine)
620{ 628{
621 return machine__process_event(machine, event); 629 return machine__process_event(machine, event, sample);
622} 630}
623 631
624void thread__find_addr_map(struct thread *self, 632void thread__find_addr_map(struct thread *thread,
625 struct machine *machine, u8 cpumode, 633 struct machine *machine, u8 cpumode,
626 enum map_type type, u64 addr, 634 enum map_type type, u64 addr,
627 struct addr_location *al) 635 struct addr_location *al)
628{ 636{
629 struct map_groups *mg = &self->mg; 637 struct map_groups *mg = &thread->mg;
630 bool load_map = false; 638 bool load_map = false;
631 639
632 al->thread = self; 640 al->thread = thread;
633 al->addr = addr; 641 al->addr = addr;
634 al->cpumode = cpumode; 642 al->cpumode = cpumode;
635 al->filtered = false; 643 al->filtered = false;
@@ -725,10 +733,10 @@ int perf_event__preprocess_sample(const union perf_event *event,
725 return -1; 733 return -1;
726 734
727 if (symbol_conf.comm_list && 735 if (symbol_conf.comm_list &&
728 !strlist__has_entry(symbol_conf.comm_list, thread->comm)) 736 !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread)))
729 goto out_filtered; 737 goto out_filtered;
730 738
731 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); 739 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid);
732 /* 740 /*
733 * Have we already created the kernel maps for this machine? 741 * Have we already created the kernel maps for this machine?
734 * 742 *
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c67ecc457d29..30fec9901e44 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -61,6 +61,12 @@ struct read_event {
61 u64 id; 61 u64 id;
62}; 62};
63 63
64struct throttle_event {
65 struct perf_event_header header;
66 u64 time;
67 u64 id;
68 u64 stream_id;
69};
64 70
65#define PERF_SAMPLE_MASK \ 71#define PERF_SAMPLE_MASK \
66 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ 72 (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
@@ -69,6 +75,9 @@ struct read_event {
69 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \ 75 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | \
70 PERF_SAMPLE_IDENTIFIER) 76 PERF_SAMPLE_IDENTIFIER)
71 77
78/* perf sample has 16 bits size limit */
79#define PERF_SAMPLE_MAX_SIZE (1 << 16)
80
72struct sample_event { 81struct sample_event {
73 struct perf_event_header header; 82 struct perf_event_header header;
74 u64 array[]; 83 u64 array[];
@@ -111,6 +120,7 @@ struct perf_sample {
111 u64 stream_id; 120 u64 stream_id;
112 u64 period; 121 u64 period;
113 u64 weight; 122 u64 weight;
123 u64 transaction;
114 u32 cpu; 124 u32 cpu;
115 u32 raw_size; 125 u32 raw_size;
116 u64 data_src; 126 u64 data_src;
@@ -177,6 +187,7 @@ union perf_event {
177 struct fork_event fork; 187 struct fork_event fork;
178 struct lost_event lost; 188 struct lost_event lost;
179 struct read_event read; 189 struct read_event read;
190 struct throttle_event throttle;
180 struct sample_event sample; 191 struct sample_event sample;
181 struct attr_event attr; 192 struct attr_event attr;
182 struct event_type_event event_type; 193 struct event_type_event event_type;
@@ -197,10 +208,10 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool,
197int perf_event__synthesize_thread_map(struct perf_tool *tool, 208int perf_event__synthesize_thread_map(struct perf_tool *tool,
198 struct thread_map *threads, 209 struct thread_map *threads,
199 perf_event__handler_t process, 210 perf_event__handler_t process,
200 struct machine *machine); 211 struct machine *machine, bool mmap_data);
201int perf_event__synthesize_threads(struct perf_tool *tool, 212int perf_event__synthesize_threads(struct perf_tool *tool,
202 perf_event__handler_t process, 213 perf_event__handler_t process,
203 struct machine *machine); 214 struct machine *machine, bool mmap_data);
204int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 215int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
205 perf_event__handler_t process, 216 perf_event__handler_t process,
206 struct machine *machine, 217 struct machine *machine,
@@ -240,7 +251,8 @@ int perf_event__process(struct perf_tool *tool,
240 struct machine *machine); 251 struct machine *machine);
241 252
242struct addr_location; 253struct addr_location;
243int perf_event__preprocess_sample(const union perf_event *self, 254
255int perf_event__preprocess_sample(const union perf_event *event,
244 struct machine *machine, 256 struct machine *machine,
245 struct addr_location *al, 257 struct addr_location *al,
246 struct perf_sample *sample); 258 struct perf_sample *sample);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f9f77bee0b1b..bbc746aa5716 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -18,6 +18,7 @@
18#include <unistd.h> 18#include <unistd.h>
19 19
20#include "parse-events.h" 20#include "parse-events.h"
21#include "parse-options.h"
21 22
22#include <sys/mman.h> 23#include <sys/mman.h>
23 24
@@ -49,6 +50,18 @@ struct perf_evlist *perf_evlist__new(void)
49 return evlist; 50 return evlist;
50} 51}
51 52
53struct perf_evlist *perf_evlist__new_default(void)
54{
55 struct perf_evlist *evlist = perf_evlist__new();
56
57 if (evlist && perf_evlist__add_default(evlist)) {
58 perf_evlist__delete(evlist);
59 evlist = NULL;
60 }
61
62 return evlist;
63}
64
52/** 65/**
53 * perf_evlist__set_id_pos - set the positions of event ids. 66 * perf_evlist__set_id_pos - set the positions of event ids.
54 * @evlist: selected event list 67 * @evlist: selected event list
@@ -104,6 +117,8 @@ void perf_evlist__delete(struct perf_evlist *evlist)
104void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) 117void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
105{ 118{
106 list_add_tail(&entry->node, &evlist->entries); 119 list_add_tail(&entry->node, &evlist->entries);
120 entry->idx = evlist->nr_entries;
121
107 if (!evlist->nr_entries++) 122 if (!evlist->nr_entries++)
108 perf_evlist__set_id_pos(evlist); 123 perf_evlist__set_id_pos(evlist);
109} 124}
@@ -152,7 +167,7 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
152 167
153 event_attr_init(&attr); 168 event_attr_init(&attr);
154 169
155 evsel = perf_evsel__new(&attr, 0); 170 evsel = perf_evsel__new(&attr);
156 if (evsel == NULL) 171 if (evsel == NULL)
157 goto error; 172 goto error;
158 173
@@ -177,7 +192,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist,
177 size_t i; 192 size_t i;
178 193
179 for (i = 0; i < nr_attrs; i++) { 194 for (i = 0; i < nr_attrs; i++) {
180 evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i); 195 evsel = perf_evsel__new_idx(attrs + i, evlist->nr_entries + i);
181 if (evsel == NULL) 196 if (evsel == NULL)
182 goto out_delete_partial_list; 197 goto out_delete_partial_list;
183 list_add_tail(&evsel->node, &head); 198 list_add_tail(&evsel->node, &head);
@@ -236,13 +251,12 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
236int perf_evlist__add_newtp(struct perf_evlist *evlist, 251int perf_evlist__add_newtp(struct perf_evlist *evlist,
237 const char *sys, const char *name, void *handler) 252 const char *sys, const char *name, void *handler)
238{ 253{
239 struct perf_evsel *evsel; 254 struct perf_evsel *evsel = perf_evsel__newtp(sys, name);
240 255
241 evsel = perf_evsel__newtp(sys, name, evlist->nr_entries);
242 if (evsel == NULL) 256 if (evsel == NULL)
243 return -1; 257 return -1;
244 258
245 evsel->handler.func = handler; 259 evsel->handler = handler;
246 perf_evlist__add(evlist, evsel); 260 perf_evlist__add(evlist, evsel);
247 return 0; 261 return 0;
248} 262}
@@ -527,7 +541,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
527 if ((old & md->mask) + size != ((old + size) & md->mask)) { 541 if ((old & md->mask) + size != ((old + size) & md->mask)) {
528 unsigned int offset = old; 542 unsigned int offset = old;
529 unsigned int len = min(sizeof(*event), size), cpy; 543 unsigned int len = min(sizeof(*event), size), cpy;
530 void *dst = &md->event_copy; 544 void *dst = md->event_copy;
531 545
532 do { 546 do {
533 cpy = min(md->mask + 1 - (offset & md->mask), len); 547 cpy = min(md->mask + 1 - (offset & md->mask), len);
@@ -537,7 +551,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
537 len -= cpy; 551 len -= cpy;
538 } while (len); 552 } while (len);
539 553
540 event = &md->event_copy; 554 event = (union perf_event *) md->event_copy;
541 } 555 }
542 556
543 old += size; 557 old += size;
@@ -545,12 +559,19 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
545 559
546 md->prev = old; 560 md->prev = old;
547 561
548 if (!evlist->overwrite)
549 perf_mmap__write_tail(md, old);
550
551 return event; 562 return event;
552} 563}
553 564
565void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
566{
567 if (!evlist->overwrite) {
568 struct perf_mmap *md = &evlist->mmap[idx];
569 unsigned int old = md->prev;
570
571 perf_mmap__write_tail(md, old);
572 }
573}
574
554static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) 575static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
555{ 576{
556 if (evlist->mmap[idx].base != NULL) { 577 if (evlist->mmap[idx].base != NULL) {
@@ -587,6 +608,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
587 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, 608 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot,
588 MAP_SHARED, fd, 0); 609 MAP_SHARED, fd, 0);
589 if (evlist->mmap[idx].base == MAP_FAILED) { 610 if (evlist->mmap[idx].base == MAP_FAILED) {
611 pr_debug2("failed to mmap perf event ring buffer, error %d\n",
612 errno);
590 evlist->mmap[idx].base = NULL; 613 evlist->mmap[idx].base = NULL;
591 return -1; 614 return -1;
592 } 615 }
@@ -595,9 +618,36 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
595 return 0; 618 return 0;
596} 619}
597 620
598static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int mask) 621static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
622 int prot, int mask, int cpu, int thread,
623 int *output)
599{ 624{
600 struct perf_evsel *evsel; 625 struct perf_evsel *evsel;
626
627 list_for_each_entry(evsel, &evlist->entries, node) {
628 int fd = FD(evsel, cpu, thread);
629
630 if (*output == -1) {
631 *output = fd;
632 if (__perf_evlist__mmap(evlist, idx, prot, mask,
633 *output) < 0)
634 return -1;
635 } else {
636 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
637 return -1;
638 }
639
640 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
641 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
642 return -1;
643 }
644
645 return 0;
646}
647
648static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
649 int mask)
650{
601 int cpu, thread; 651 int cpu, thread;
602 int nr_cpus = cpu_map__nr(evlist->cpus); 652 int nr_cpus = cpu_map__nr(evlist->cpus);
603 int nr_threads = thread_map__nr(evlist->threads); 653 int nr_threads = thread_map__nr(evlist->threads);
@@ -607,23 +657,9 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
607 int output = -1; 657 int output = -1;
608 658
609 for (thread = 0; thread < nr_threads; thread++) { 659 for (thread = 0; thread < nr_threads; thread++) {
610 list_for_each_entry(evsel, &evlist->entries, node) { 660 if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask,
611 int fd = FD(evsel, cpu, thread); 661 cpu, thread, &output))
612 662 goto out_unmap;
613 if (output == -1) {
614 output = fd;
615 if (__perf_evlist__mmap(evlist, cpu,
616 prot, mask, output) < 0)
617 goto out_unmap;
618 } else {
619 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
620 goto out_unmap;
621 }
622
623 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
624 perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
625 goto out_unmap;
626 }
627 } 663 }
628 } 664 }
629 665
@@ -635,9 +671,9 @@ out_unmap:
635 return -1; 671 return -1;
636} 672}
637 673
638static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, int mask) 674static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
675 int mask)
639{ 676{
640 struct perf_evsel *evsel;
641 int thread; 677 int thread;
642 int nr_threads = thread_map__nr(evlist->threads); 678 int nr_threads = thread_map__nr(evlist->threads);
643 679
@@ -645,23 +681,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
645 for (thread = 0; thread < nr_threads; thread++) { 681 for (thread = 0; thread < nr_threads; thread++) {
646 int output = -1; 682 int output = -1;
647 683
648 list_for_each_entry(evsel, &evlist->entries, node) { 684 if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0,
649 int fd = FD(evsel, 0, thread); 685 thread, &output))
650 686 goto out_unmap;
651 if (output == -1) {
652 output = fd;
653 if (__perf_evlist__mmap(evlist, thread,
654 prot, mask, output) < 0)
655 goto out_unmap;
656 } else {
657 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, output) != 0)
658 goto out_unmap;
659 }
660
661 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
662 perf_evlist__id_add_fd(evlist, evsel, 0, thread, fd) < 0)
663 goto out_unmap;
664 }
665 } 687 }
666 688
667 return 0; 689 return 0;
@@ -672,20 +694,90 @@ out_unmap:
672 return -1; 694 return -1;
673} 695}
674 696
675/** perf_evlist__mmap - Create per cpu maps to receive events 697static size_t perf_evlist__mmap_size(unsigned long pages)
676 * 698{
677 * @evlist - list of events 699 /* 512 kiB: default amount of unprivileged mlocked memory */
678 * @pages - map length in pages 700 if (pages == UINT_MAX)
679 * @overwrite - overwrite older events? 701 pages = (512 * 1024) / page_size;
680 * 702 else if (!is_power_of_2(pages))
681 * If overwrite is false the user needs to signal event consuption using: 703 return 0;
682 * 704
683 * struct perf_mmap *m = &evlist->mmap[cpu]; 705 return (pages + 1) * page_size;
684 * unsigned int head = perf_mmap__read_head(m); 706}
707
708static long parse_pages_arg(const char *str, unsigned long min,
709 unsigned long max)
710{
711 unsigned long pages, val;
712 static struct parse_tag tags[] = {
713 { .tag = 'B', .mult = 1 },
714 { .tag = 'K', .mult = 1 << 10 },
715 { .tag = 'M', .mult = 1 << 20 },
716 { .tag = 'G', .mult = 1 << 30 },
717 { .tag = 0 },
718 };
719
720 if (str == NULL)
721 return -EINVAL;
722
723 val = parse_tag_value(str, tags);
724 if (val != (unsigned long) -1) {
725 /* we got file size value */
726 pages = PERF_ALIGN(val, page_size) / page_size;
727 } else {
728 /* we got pages count value */
729 char *eptr;
730 pages = strtoul(str, &eptr, 10);
731 if (*eptr != '\0')
732 return -EINVAL;
733 }
734
735 if ((pages == 0) && (min == 0)) {
736 /* leave number of pages at 0 */
737 } else if (pages < (1UL << 31) && !is_power_of_2(pages)) {
738 /* round pages up to next power of 2 */
739 pages = next_pow2(pages);
740 pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n",
741 pages * page_size, pages);
742 }
743
744 if (pages > max)
745 return -EINVAL;
746
747 return pages;
748}
749
750int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
751 int unset __maybe_unused)
752{
753 unsigned int *mmap_pages = opt->value;
754 unsigned long max = UINT_MAX;
755 long pages;
756
757 if (max < SIZE_MAX / page_size)
758 max = SIZE_MAX / page_size;
759
760 pages = parse_pages_arg(str, 1, max);
761 if (pages < 0) {
762 pr_err("Invalid argument for --mmap_pages/-m\n");
763 return -1;
764 }
765
766 *mmap_pages = pages;
767 return 0;
768}
769
770/**
771 * perf_evlist__mmap - Create mmaps to receive events.
772 * @evlist: list of events
773 * @pages: map length in pages
774 * @overwrite: overwrite older events?
685 * 775 *
686 * perf_mmap__write_tail(m, head) 776 * If @overwrite is %false the user needs to signal event consumption using
777 * perf_mmap__write_tail(). Using perf_evlist__mmap_read() does this
778 * automatically.
687 * 779 *
688 * Using perf_evlist__read_on_cpu does this automatically. 780 * Return: %0 on success, negative error code otherwise.
689 */ 781 */
690int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 782int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
691 bool overwrite) 783 bool overwrite)
@@ -695,14 +787,6 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
695 const struct thread_map *threads = evlist->threads; 787 const struct thread_map *threads = evlist->threads;
696 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; 788 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask;
697 789
698 /* 512 kiB: default amount of unprivileged mlocked memory */
699 if (pages == UINT_MAX)
700 pages = (512 * 1024) / page_size;
701 else if (!is_power_of_2(pages))
702 return -EINVAL;
703
704 mask = pages * page_size - 1;
705
706 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 790 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
707 return -ENOMEM; 791 return -ENOMEM;
708 792
@@ -710,7 +794,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
710 return -ENOMEM; 794 return -ENOMEM;
711 795
712 evlist->overwrite = overwrite; 796 evlist->overwrite = overwrite;
713 evlist->mmap_len = (pages + 1) * page_size; 797 evlist->mmap_len = perf_evlist__mmap_size(pages);
798 pr_debug("mmap size %zuB\n", evlist->mmap_len);
799 mask = evlist->mmap_len - page_size - 1;
714 800
715 list_for_each_entry(evsel, &evlist->entries, node) { 801 list_for_each_entry(evsel, &evlist->entries, node) {
716 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 802 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -725,8 +811,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
725 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 811 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
726} 812}
727 813
728int perf_evlist__create_maps(struct perf_evlist *evlist, 814int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
729 struct perf_target *target)
730{ 815{
731 evlist->threads = thread_map__new_str(target->pid, target->tid, 816 evlist->threads = thread_map__new_str(target->pid, target->tid,
732 target->uid); 817 target->uid);
@@ -734,9 +819,11 @@ int perf_evlist__create_maps(struct perf_evlist *evlist,
734 if (evlist->threads == NULL) 819 if (evlist->threads == NULL)
735 return -1; 820 return -1;
736 821
737 if (perf_target__has_task(target)) 822 if (target->force_per_cpu)
823 evlist->cpus = cpu_map__new(target->cpu_list);
824 else if (target__has_task(target))
738 evlist->cpus = cpu_map__dummy_new(); 825 evlist->cpus = cpu_map__dummy_new();
739 else if (!perf_target__has_cpu(target) && !target->uses_mmap) 826 else if (!target__has_cpu(target) && !target->uses_mmap)
740 evlist->cpus = cpu_map__dummy_new(); 827 evlist->cpus = cpu_map__dummy_new();
741 else 828 else
742 evlist->cpus = cpu_map__new(target->cpu_list); 829 evlist->cpus = cpu_map__new(target->cpu_list);
@@ -945,8 +1032,7 @@ out_err:
945 return err; 1032 return err;
946} 1033}
947 1034
948int perf_evlist__prepare_workload(struct perf_evlist *evlist, 1035int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target,
949 struct perf_target *target,
950 const char *argv[], bool pipe_output, 1036 const char *argv[], bool pipe_output,
951 bool want_signal) 1037 bool want_signal)
952{ 1038{
@@ -998,7 +1084,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
998 exit(-1); 1084 exit(-1);
999 } 1085 }
1000 1086
1001 if (perf_target__none(target)) 1087 if (target__none(target))
1002 evlist->threads->map[0] = evlist->workload.pid; 1088 evlist->threads->map[0] = evlist->workload.pid;
1003 1089
1004 close(child_ready_pipe[1]); 1090 close(child_ready_pipe[1]);
@@ -1064,5 +1150,68 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
1064 perf_evsel__name(evsel)); 1150 perf_evsel__name(evsel));
1065 } 1151 }
1066 1152
1067 return printed + fprintf(fp, "\n");; 1153 return printed + fprintf(fp, "\n");
1154}
1155
1156int perf_evlist__strerror_tp(struct perf_evlist *evlist __maybe_unused,
1157 int err, char *buf, size_t size)
1158{
1159 char sbuf[128];
1160
1161 switch (err) {
1162 case ENOENT:
1163 scnprintf(buf, size, "%s",
1164 "Error:\tUnable to find debugfs\n"
1165 "Hint:\tWas your kernel was compiled with debugfs support?\n"
1166 "Hint:\tIs the debugfs filesystem mounted?\n"
1167 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
1168 break;
1169 case EACCES:
1170 scnprintf(buf, size,
1171 "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
1172 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
1173 debugfs_mountpoint, debugfs_mountpoint);
1174 break;
1175 default:
1176 scnprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf)));
1177 break;
1178 }
1179
1180 return 0;
1181}
1182
1183int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1184 int err, char *buf, size_t size)
1185{
1186 int printed, value;
1187 char sbuf[128], *emsg = strerror_r(err, sbuf, sizeof(sbuf));
1188
1189 switch (err) {
1190 case EACCES:
1191 case EPERM:
1192 printed = scnprintf(buf, size,
1193 "Error:\t%s.\n"
1194 "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg);
1195
1196 if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value))
1197 break;
1198
1199 printed += scnprintf(buf + printed, size - printed, "\nHint:\t");
1200
1201 if (value >= 2) {
1202 printed += scnprintf(buf + printed, size - printed,
1203 "For your workloads it needs to be <= 1\nHint:\t");
1204 }
1205 printed += scnprintf(buf + printed, size - printed,
1206 "For system wide tracing it needs to be set to -1");
1207
1208 printed += scnprintf(buf + printed, size - printed,
1209 ".\nHint:\tThe current value is %d.", value);
1210 break;
1211 default:
1212 scnprintf(buf, size, "%s", emsg);
1213 break;
1214 }
1215
1216 return 0;
1068} 1217}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 880d7139d2fb..649d6ea98a84 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -21,7 +21,7 @@ struct perf_mmap {
21 void *base; 21 void *base;
22 int mask; 22 int mask;
23 unsigned int prev; 23 unsigned int prev;
24 union perf_event event_copy; 24 char event_copy[PERF_SAMPLE_MAX_SIZE];
25}; 25};
26 26
27struct perf_evlist { 27struct perf_evlist {
@@ -31,7 +31,7 @@ struct perf_evlist {
31 int nr_groups; 31 int nr_groups;
32 int nr_fds; 32 int nr_fds;
33 int nr_mmaps; 33 int nr_mmaps;
34 int mmap_len; 34 size_t mmap_len;
35 int id_pos; 35 int id_pos;
36 int is_pos; 36 int is_pos;
37 u64 combined_sample_type; 37 u64 combined_sample_type;
@@ -53,6 +53,7 @@ struct perf_evsel_str_handler {
53}; 53};
54 54
55struct perf_evlist *perf_evlist__new(void); 55struct perf_evlist *perf_evlist__new(void);
56struct perf_evlist *perf_evlist__new_default(void);
56void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, 57void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
57 struct thread_map *threads); 58 struct thread_map *threads);
58void perf_evlist__exit(struct perf_evlist *evlist); 59void perf_evlist__exit(struct perf_evlist *evlist);
@@ -87,7 +88,9 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id);
87 88
88struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); 89struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id);
89 90
90union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); 91union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx);
92
93void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);
91 94
92int perf_evlist__open(struct perf_evlist *evlist); 95int perf_evlist__open(struct perf_evlist *evlist);
93void perf_evlist__close(struct perf_evlist *evlist); 96void perf_evlist__close(struct perf_evlist *evlist);
@@ -96,13 +99,18 @@ void perf_evlist__set_id_pos(struct perf_evlist *evlist);
96bool perf_can_sample_identifier(void); 99bool perf_can_sample_identifier(void);
97void perf_evlist__config(struct perf_evlist *evlist, 100void perf_evlist__config(struct perf_evlist *evlist,
98 struct perf_record_opts *opts); 101 struct perf_record_opts *opts);
102int perf_record_opts__config(struct perf_record_opts *opts);
99 103
100int perf_evlist__prepare_workload(struct perf_evlist *evlist, 104int perf_evlist__prepare_workload(struct perf_evlist *evlist,
101 struct perf_target *target, 105 struct target *target,
102 const char *argv[], bool pipe_output, 106 const char *argv[], bool pipe_output,
103 bool want_signal); 107 bool want_signal);
104int perf_evlist__start_workload(struct perf_evlist *evlist); 108int perf_evlist__start_workload(struct perf_evlist *evlist);
105 109
110int perf_evlist__parse_mmap_pages(const struct option *opt,
111 const char *str,
112 int unset);
113
106int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, 114int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
107 bool overwrite); 115 bool overwrite);
108void perf_evlist__munmap(struct perf_evlist *evlist); 116void perf_evlist__munmap(struct perf_evlist *evlist);
@@ -126,8 +134,7 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
126 evlist->threads = threads; 134 evlist->threads = threads;
127} 135}
128 136
129int perf_evlist__create_maps(struct perf_evlist *evlist, 137int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target);
130 struct perf_target *target);
131void perf_evlist__delete_maps(struct perf_evlist *evlist); 138void perf_evlist__delete_maps(struct perf_evlist *evlist);
132int perf_evlist__apply_filters(struct perf_evlist *evlist); 139int perf_evlist__apply_filters(struct perf_evlist *evlist);
133 140
@@ -163,10 +170,13 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
163 170
164size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); 171size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
165 172
173int perf_evlist__strerror_tp(struct perf_evlist *evlist, int err, char *buf, size_t size);
174int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size);
175
166static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) 176static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
167{ 177{
168 struct perf_event_mmap_page *pc = mm->base; 178 struct perf_event_mmap_page *pc = mm->base;
169 int head = pc->data_head; 179 int head = ACCESS_ONCE(pc->data_head);
170 rmb(); 180 rmb();
171 return head; 181 return head;
172} 182}
@@ -179,7 +189,7 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md,
179 /* 189 /*
180 * ensure all reads are done before we write the tail out. 190 * ensure all reads are done before we write the tail out.
181 */ 191 */
182 /* mb(); */ 192 mb();
183 pc->data_tail = tail; 193 pc->data_tail = tail;
184} 194}
185 195
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 0ce9febf1ba0..46dd4c2a41ce 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -168,7 +168,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
168 perf_evsel__calc_id_pos(evsel); 168 perf_evsel__calc_id_pos(evsel);
169} 169}
170 170
171struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 171struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
172{ 172{
173 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 173 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
174 174
@@ -219,7 +219,7 @@ out:
219 return format; 219 return format;
220} 220}
221 221
222struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx) 222struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
223{ 223{
224 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 224 struct perf_evsel *evsel = zalloc(sizeof(*evsel));
225 225
@@ -645,7 +645,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
645 } 645 }
646 } 646 }
647 647
648 if (perf_target__has_cpu(&opts->target)) 648 if (target__has_cpu(&opts->target) || opts->target.force_per_cpu)
649 perf_evsel__set_sample_bit(evsel, CPU); 649 perf_evsel__set_sample_bit(evsel, CPU);
650 650
651 if (opts->period) 651 if (opts->period)
@@ -653,7 +653,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
653 653
654 if (!perf_missing_features.sample_id_all && 654 if (!perf_missing_features.sample_id_all &&
655 (opts->sample_time || !opts->no_inherit || 655 (opts->sample_time || !opts->no_inherit ||
656 perf_target__has_cpu(&opts->target))) 656 target__has_cpu(&opts->target) || opts->target.force_per_cpu))
657 perf_evsel__set_sample_bit(evsel, TIME); 657 perf_evsel__set_sample_bit(evsel, TIME);
658 658
659 if (opts->raw_samples) { 659 if (opts->raw_samples) {
@@ -663,7 +663,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
663 } 663 }
664 664
665 if (opts->sample_address) 665 if (opts->sample_address)
666 attr->sample_type |= PERF_SAMPLE_DATA_SRC; 666 perf_evsel__set_sample_bit(evsel, DATA_SRC);
667 667
668 if (opts->no_delay) { 668 if (opts->no_delay) {
669 attr->watermark = 0; 669 attr->watermark = 0;
@@ -675,12 +675,14 @@ void perf_evsel__config(struct perf_evsel *evsel,
675 } 675 }
676 676
677 if (opts->sample_weight) 677 if (opts->sample_weight)
678 attr->sample_type |= PERF_SAMPLE_WEIGHT; 678 perf_evsel__set_sample_bit(evsel, WEIGHT);
679 679
680 attr->mmap = track; 680 attr->mmap = track;
681 attr->mmap2 = track && !perf_missing_features.mmap2;
682 attr->comm = track; 681 attr->comm = track;
683 682
683 if (opts->sample_transaction)
684 perf_evsel__set_sample_bit(evsel, TRANSACTION);
685
684 /* 686 /*
685 * XXX see the function comment above 687 * XXX see the function comment above
686 * 688 *
@@ -694,7 +696,7 @@ void perf_evsel__config(struct perf_evsel *evsel,
694 * Setting enable_on_exec for independent events and 696 * Setting enable_on_exec for independent events and
695 * group leaders for traced executed by perf. 697 * group leaders for traced executed by perf.
696 */ 698 */
697 if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) 699 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel))
698 attr->enable_on_exec = 1; 700 attr->enable_on_exec = 1;
699} 701}
700 702
@@ -983,6 +985,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
983 ret += PRINT_ATTR2(exclude_host, exclude_guest); 985 ret += PRINT_ATTR2(exclude_host, exclude_guest);
984 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, 986 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
985 "excl.callchain_user", exclude_callchain_user); 987 "excl.callchain_user", exclude_callchain_user);
988 ret += PRINT_ATTR_U32(mmap2);
986 989
987 ret += PRINT_ATTR_U32(wakeup_events); 990 ret += PRINT_ATTR_U32(wakeup_events);
988 ret += PRINT_ATTR_U32(wakeup_watermark); 991 ret += PRINT_ATTR_U32(wakeup_watermark);
@@ -1048,6 +1051,8 @@ retry_open:
1048 group_fd, flags); 1051 group_fd, flags);
1049 if (FD(evsel, cpu, thread) < 0) { 1052 if (FD(evsel, cpu, thread) < 0) {
1050 err = -errno; 1053 err = -errno;
1054 pr_debug2("perf_event_open failed, error %d\n",
1055 err);
1051 goto try_fallback; 1056 goto try_fallback;
1052 } 1057 }
1053 set_rlimit = NO_CHANGE; 1058 set_rlimit = NO_CHANGE;
@@ -1214,6 +1219,7 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel,
1214 1219
1215 sample->pid = u.val32[0]; 1220 sample->pid = u.val32[0];
1216 sample->tid = u.val32[1]; 1221 sample->tid = u.val32[1];
1222 array--;
1217 } 1223 }
1218 1224
1219 return 0; 1225 return 0;
@@ -1453,6 +1459,9 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1453 array = (void *)array + sz; 1459 array = (void *)array + sz;
1454 OVERFLOW_CHECK_u64(array); 1460 OVERFLOW_CHECK_u64(array);
1455 data->user_stack.size = *array++; 1461 data->user_stack.size = *array++;
1462 if (WARN_ONCE(data->user_stack.size > sz,
1463 "user stack dump failure\n"))
1464 return -EFAULT;
1456 } 1465 }
1457 } 1466 }
1458 1467
@@ -1470,6 +1479,13 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1470 array++; 1479 array++;
1471 } 1480 }
1472 1481
1482 data->transaction = 0;
1483 if (type & PERF_SAMPLE_TRANSACTION) {
1484 OVERFLOW_CHECK_u64(array);
1485 data->transaction = *array;
1486 array++;
1487 }
1488
1473 return 0; 1489 return 0;
1474} 1490}
1475 1491
@@ -1562,6 +1578,9 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
1562 if (type & PERF_SAMPLE_DATA_SRC) 1578 if (type & PERF_SAMPLE_DATA_SRC)
1563 result += sizeof(u64); 1579 result += sizeof(u64);
1564 1580
1581 if (type & PERF_SAMPLE_TRANSACTION)
1582 result += sizeof(u64);
1583
1565 return result; 1584 return result;
1566} 1585}
1567 1586
@@ -1735,6 +1754,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
1735 array++; 1754 array++;
1736 } 1755 }
1737 1756
1757 if (type & PERF_SAMPLE_TRANSACTION) {
1758 *array = sample->transaction;
1759 array++;
1760 }
1761
1738 return 0; 1762 return 0;
1739} 1763}
1740 1764
@@ -1982,8 +2006,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
1982 return false; 2006 return false;
1983} 2007}
1984 2008
1985int perf_evsel__open_strerror(struct perf_evsel *evsel, 2009int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
1986 struct perf_target *target,
1987 int err, char *msg, size_t size) 2010 int err, char *msg, size_t size)
1988{ 2011{
1989 switch (err) { 2012 switch (err) {
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 4a7bdc713bab..1ea7c92e6e33 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -74,10 +74,7 @@ struct perf_evsel {
74 off_t id_offset; 74 off_t id_offset;
75 }; 75 };
76 struct cgroup_sel *cgrp; 76 struct cgroup_sel *cgrp;
77 struct { 77 void *handler;
78 void *func;
79 void *data;
80 } handler;
81 struct cpu_map *cpus; 78 struct cpu_map *cpus;
82 unsigned int sample_size; 79 unsigned int sample_size;
83 int id_pos; 80 int id_pos;
@@ -99,8 +96,19 @@ struct thread_map;
99struct perf_evlist; 96struct perf_evlist;
100struct perf_record_opts; 97struct perf_record_opts;
101 98
102struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); 99struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx);
103struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx); 100
101static inline struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr)
102{
103 return perf_evsel__new_idx(attr, 0);
104}
105
106struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx);
107
108static inline struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name)
109{
110 return perf_evsel__newtp_idx(sys, name, 0);
111}
104 112
105struct event_format *event_format__new(const char *sys, const char *name); 113struct event_format *event_format__new(const char *sys, const char *name);
106 114
@@ -197,6 +205,12 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,
197 (e1->attr.config == e2->attr.config); 205 (e1->attr.config == e2->attr.config);
198} 206}
199 207
208#define perf_evsel__cmp(a, b) \
209 ((a) && \
210 (b) && \
211 (a)->attr.type == (b)->attr.type && \
212 (a)->attr.config == (b)->attr.config)
213
200int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 214int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
201 int cpu, int thread, bool scale); 215 int cpu, int thread, bool scale);
202 216
@@ -265,6 +279,11 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel)
265 return list_entry(evsel->node.next, struct perf_evsel, node); 279 return list_entry(evsel->node.next, struct perf_evsel, node);
266} 280}
267 281
282static inline struct perf_evsel *perf_evsel__prev(struct perf_evsel *evsel)
283{
284 return list_entry(evsel->node.prev, struct perf_evsel, node);
285}
286
268/** 287/**
269 * perf_evsel__is_group_leader - Return whether given evsel is a leader event 288 * perf_evsel__is_group_leader - Return whether given evsel is a leader event
270 * 289 *
@@ -304,8 +323,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
304 323
305bool perf_evsel__fallback(struct perf_evsel *evsel, int err, 324bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
306 char *msg, size_t msgsize); 325 char *msg, size_t msgsize);
307int perf_evsel__open_strerror(struct perf_evsel *evsel, 326int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
308 struct perf_target *target,
309 int err, char *msg, size_t size); 327 int err, char *msg, size_t size);
310 328
311static inline int perf_evsel__group_idx(struct perf_evsel *evsel) 329static inline int perf_evsel__group_idx(struct perf_evsel *evsel)
diff --git a/tools/perf/util/fs.c b/tools/perf/util/fs.c
new file mode 100644
index 000000000000..f5be1f26e724
--- /dev/null
+++ b/tools/perf/util/fs.c
@@ -0,0 +1,119 @@
1
2/* TODO merge/factor into tools/lib/lk/debugfs.c */
3
4#include "util.h"
5#include "util/fs.h"
6
7static const char * const sysfs__fs_known_mountpoints[] = {
8 "/sys",
9 0,
10};
11
12static const char * const procfs__known_mountpoints[] = {
13 "/proc",
14 0,
15};
16
17struct fs {
18 const char *name;
19 const char * const *mounts;
20 char path[PATH_MAX + 1];
21 bool found;
22 long magic;
23};
24
25enum {
26 FS__SYSFS = 0,
27 FS__PROCFS = 1,
28};
29
30static struct fs fs__entries[] = {
31 [FS__SYSFS] = {
32 .name = "sysfs",
33 .mounts = sysfs__fs_known_mountpoints,
34 .magic = SYSFS_MAGIC,
35 },
36 [FS__PROCFS] = {
37 .name = "proc",
38 .mounts = procfs__known_mountpoints,
39 .magic = PROC_SUPER_MAGIC,
40 },
41};
42
43static bool fs__read_mounts(struct fs *fs)
44{
45 bool found = false;
46 char type[100];
47 FILE *fp;
48
49 fp = fopen("/proc/mounts", "r");
50 if (fp == NULL)
51 return NULL;
52
53 while (!found &&
54 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
55 fs->path, type) == 2) {
56
57 if (strcmp(type, fs->name) == 0)
58 found = true;
59 }
60
61 fclose(fp);
62 return fs->found = found;
63}
64
65static int fs__valid_mount(const char *fs, long magic)
66{
67 struct statfs st_fs;
68
69 if (statfs(fs, &st_fs) < 0)
70 return -ENOENT;
71 else if (st_fs.f_type != magic)
72 return -ENOENT;
73
74 return 0;
75}
76
77static bool fs__check_mounts(struct fs *fs)
78{
79 const char * const *ptr;
80
81 ptr = fs->mounts;
82 while (*ptr) {
83 if (fs__valid_mount(*ptr, fs->magic) == 0) {
84 fs->found = true;
85 strcpy(fs->path, *ptr);
86 return true;
87 }
88 ptr++;
89 }
90
91 return false;
92}
93
94static const char *fs__get_mountpoint(struct fs *fs)
95{
96 if (fs__check_mounts(fs))
97 return fs->path;
98
99 return fs__read_mounts(fs) ? fs->path : NULL;
100}
101
102static const char *fs__mountpoint(int idx)
103{
104 struct fs *fs = &fs__entries[idx];
105
106 if (fs->found)
107 return (const char *)fs->path;
108
109 return fs__get_mountpoint(fs);
110}
111
112#define FS__MOUNTPOINT(name, idx) \
113const char *name##__mountpoint(void) \
114{ \
115 return fs__mountpoint(idx); \
116}
117
118FS__MOUNTPOINT(sysfs, FS__SYSFS);
119FS__MOUNTPOINT(procfs, FS__PROCFS);
diff --git a/tools/perf/util/fs.h b/tools/perf/util/fs.h
new file mode 100644
index 000000000000..5e09ce1bab0e
--- /dev/null
+++ b/tools/perf/util/fs.h
@@ -0,0 +1,7 @@
1#ifndef __PERF_FS
2#define __PERF_FS
3
4const char *sysfs__mountpoint(void);
5const char *procfs__mountpoint(void);
6
7#endif /* __PERF_FS */
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
index 3ac38031d534..36a885d2cd22 100755
--- a/tools/perf/util/generate-cmdlist.sh
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -22,7 +22,7 @@ do
22 }' "Documentation/perf-$cmd.txt" 22 }' "Documentation/perf-$cmd.txt"
23done 23done
24 24
25echo "#ifdef LIBELF_SUPPORT" 25echo "#ifdef HAVE_LIBELF_SUPPORT"
26sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt | 26sed -n -e 's/^perf-\([^ ]*\)[ ].* full.*/\1/p' command-list.txt |
27sort | 27sort |
28while read cmd 28while read cmd
@@ -35,5 +35,5 @@ do
35 p 35 p
36 }' "Documentation/perf-$cmd.txt" 36 }' "Documentation/perf-$cmd.txt"
37done 37done
38echo "#endif /* LIBELF_SUPPORT */" 38echo "#endif /* HAVE_LIBELF_SUPPORT */"
39echo "};" 39echo "};"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index c3e5a3b817ab..369c03648f88 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -22,6 +22,7 @@
22#include "vdso.h" 22#include "vdso.h"
23#include "strbuf.h" 23#include "strbuf.h"
24#include "build-id.h" 24#include "build-id.h"
25#include "data.h"
25 26
26static bool no_buildid_cache = false; 27static bool no_buildid_cache = false;
27 28
@@ -2189,7 +2190,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
2189{ 2190{
2190 struct header_print_data hd; 2191 struct header_print_data hd;
2191 struct perf_header *header = &session->header; 2192 struct perf_header *header = &session->header;
2192 int fd = session->fd; 2193 int fd = perf_data_file__fd(session->file);
2193 hd.fp = fp; 2194 hd.fp = fp;
2194 hd.full = full; 2195 hd.full = full;
2195 2196
@@ -2650,7 +2651,8 @@ static int perf_header__read_pipe(struct perf_session *session)
2650 struct perf_header *header = &session->header; 2651 struct perf_header *header = &session->header;
2651 struct perf_pipe_file_header f_header; 2652 struct perf_pipe_file_header f_header;
2652 2653
2653 if (perf_file_header__read_pipe(&f_header, header, session->fd, 2654 if (perf_file_header__read_pipe(&f_header, header,
2655 perf_data_file__fd(session->file),
2654 session->repipe) < 0) { 2656 session->repipe) < 0) {
2655 pr_debug("incompatible file format\n"); 2657 pr_debug("incompatible file format\n");
2656 return -EINVAL; 2658 return -EINVAL;
@@ -2751,18 +2753,19 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
2751 2753
2752int perf_session__read_header(struct perf_session *session) 2754int perf_session__read_header(struct perf_session *session)
2753{ 2755{
2756 struct perf_data_file *file = session->file;
2754 struct perf_header *header = &session->header; 2757 struct perf_header *header = &session->header;
2755 struct perf_file_header f_header; 2758 struct perf_file_header f_header;
2756 struct perf_file_attr f_attr; 2759 struct perf_file_attr f_attr;
2757 u64 f_id; 2760 u64 f_id;
2758 int nr_attrs, nr_ids, i, j; 2761 int nr_attrs, nr_ids, i, j;
2759 int fd = session->fd; 2762 int fd = perf_data_file__fd(file);
2760 2763
2761 session->evlist = perf_evlist__new(); 2764 session->evlist = perf_evlist__new();
2762 if (session->evlist == NULL) 2765 if (session->evlist == NULL)
2763 return -ENOMEM; 2766 return -ENOMEM;
2764 2767
2765 if (session->fd_pipe) 2768 if (perf_data_file__is_pipe(file))
2766 return perf_header__read_pipe(session); 2769 return perf_header__read_pipe(session);
2767 2770
2768 if (perf_file_header__read(&f_header, header, fd) < 0) 2771 if (perf_file_header__read(&f_header, header, fd) < 0)
@@ -2777,7 +2780,7 @@ int perf_session__read_header(struct perf_session *session)
2777 if (f_header.data.size == 0) { 2780 if (f_header.data.size == 0) {
2778 pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n" 2781 pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
2779 "Was the 'perf record' command properly terminated?\n", 2782 "Was the 'perf record' command properly terminated?\n",
2780 session->filename); 2783 file->path);
2781 } 2784 }
2782 2785
2783 nr_attrs = f_header.attrs.size / f_header.attr_size; 2786 nr_attrs = f_header.attrs.size / f_header.attr_size;
@@ -2794,7 +2797,7 @@ int perf_session__read_header(struct perf_session *session)
2794 perf_event__attr_swap(&f_attr.attr); 2797 perf_event__attr_swap(&f_attr.attr);
2795 2798
2796 tmp = lseek(fd, 0, SEEK_CUR); 2799 tmp = lseek(fd, 0, SEEK_CUR);
2797 evsel = perf_evsel__new(&f_attr.attr, i); 2800 evsel = perf_evsel__new(&f_attr.attr);
2798 2801
2799 if (evsel == NULL) 2802 if (evsel == NULL)
2800 goto out_delete_evlist; 2803 goto out_delete_evlist;
@@ -2913,7 +2916,7 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
2913 return -ENOMEM; 2916 return -ENOMEM;
2914 } 2917 }
2915 2918
2916 evsel = perf_evsel__new(&event->attr.attr, evlist->nr_entries); 2919 evsel = perf_evsel__new(&event->attr.attr);
2917 if (evsel == NULL) 2920 if (evsel == NULL)
2918 return -ENOMEM; 2921 return -ENOMEM;
2919 2922
@@ -2990,18 +2993,19 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
2990 struct perf_session *session) 2993 struct perf_session *session)
2991{ 2994{
2992 ssize_t size_read, padding, size = event->tracing_data.size; 2995 ssize_t size_read, padding, size = event->tracing_data.size;
2993 off_t offset = lseek(session->fd, 0, SEEK_CUR); 2996 int fd = perf_data_file__fd(session->file);
2997 off_t offset = lseek(fd, 0, SEEK_CUR);
2994 char buf[BUFSIZ]; 2998 char buf[BUFSIZ];
2995 2999
2996 /* setup for reading amidst mmap */ 3000 /* setup for reading amidst mmap */
2997 lseek(session->fd, offset + sizeof(struct tracing_data_event), 3001 lseek(fd, offset + sizeof(struct tracing_data_event),
2998 SEEK_SET); 3002 SEEK_SET);
2999 3003
3000 size_read = trace_report(session->fd, &session->pevent, 3004 size_read = trace_report(fd, &session->pevent,
3001 session->repipe); 3005 session->repipe);
3002 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 3006 padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
3003 3007
3004 if (readn(session->fd, buf, padding) < 0) { 3008 if (readn(fd, buf, padding) < 0) {
3005 pr_err("%s: reading input file", __func__); 3009 pr_err("%s: reading input file", __func__);
3006 return -1; 3010 return -1;
3007 } 3011 }
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 9ff6cf3e9a99..822903eaa201 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -160,6 +160,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
160 hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); 160 hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
161 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); 161 hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
162 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); 162 hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
163
164 if (h->transaction)
165 hists__new_col_len(hists, HISTC_TRANSACTION,
166 hist_entry__transaction_len());
163} 167}
164 168
165void hists__output_recalc_col_len(struct hists *hists, int max_rows) 169void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -346,7 +350,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
346 struct rb_node **p; 350 struct rb_node **p;
347 struct rb_node *parent = NULL; 351 struct rb_node *parent = NULL;
348 struct hist_entry *he; 352 struct hist_entry *he;
349 int cmp; 353 int64_t cmp;
350 354
351 p = &hists->entries_in->rb_node; 355 p = &hists->entries_in->rb_node;
352 356
@@ -395,6 +399,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
395 if (!he) 399 if (!he)
396 return NULL; 400 return NULL;
397 401
402 hists->nr_entries++;
398 rb_link_node(&he->rb_node_in, parent, p); 403 rb_link_node(&he->rb_node_in, parent, p);
399 rb_insert_color(&he->rb_node_in, hists->entries_in); 404 rb_insert_color(&he->rb_node_in, hists->entries_in);
400out: 405out:
@@ -402,74 +407,16 @@ out:
402 return he; 407 return he;
403} 408}
404 409
405struct hist_entry *__hists__add_mem_entry(struct hists *self, 410struct hist_entry *__hists__add_entry(struct hists *hists,
406 struct addr_location *al,
407 struct symbol *sym_parent,
408 struct mem_info *mi,
409 u64 period,
410 u64 weight)
411{
412 struct hist_entry entry = {
413 .thread = al->thread,
414 .ms = {
415 .map = al->map,
416 .sym = al->sym,
417 },
418 .stat = {
419 .period = period,
420 .weight = weight,
421 .nr_events = 1,
422 },
423 .cpu = al->cpu,
424 .ip = al->addr,
425 .level = al->level,
426 .parent = sym_parent,
427 .filtered = symbol__parent_filter(sym_parent),
428 .hists = self,
429 .mem_info = mi,
430 .branch_info = NULL,
431 };
432 return add_hist_entry(self, &entry, al, period, weight);
433}
434
435struct hist_entry *__hists__add_branch_entry(struct hists *self,
436 struct addr_location *al,
437 struct symbol *sym_parent,
438 struct branch_info *bi,
439 u64 period,
440 u64 weight)
441{
442 struct hist_entry entry = {
443 .thread = al->thread,
444 .ms = {
445 .map = bi->to.map,
446 .sym = bi->to.sym,
447 },
448 .cpu = al->cpu,
449 .ip = bi->to.addr,
450 .level = al->level,
451 .stat = {
452 .period = period,
453 .nr_events = 1,
454 .weight = weight,
455 },
456 .parent = sym_parent,
457 .filtered = symbol__parent_filter(sym_parent),
458 .branch_info = bi,
459 .hists = self,
460 .mem_info = NULL,
461 };
462
463 return add_hist_entry(self, &entry, al, period, weight);
464}
465
466struct hist_entry *__hists__add_entry(struct hists *self,
467 struct addr_location *al, 411 struct addr_location *al,
468 struct symbol *sym_parent, u64 period, 412 struct symbol *sym_parent,
469 u64 weight) 413 struct branch_info *bi,
414 struct mem_info *mi,
415 u64 period, u64 weight, u64 transaction)
470{ 416{
471 struct hist_entry entry = { 417 struct hist_entry entry = {
472 .thread = al->thread, 418 .thread = al->thread,
419 .comm = thread__comm(al->thread),
473 .ms = { 420 .ms = {
474 .map = al->map, 421 .map = al->map,
475 .sym = al->sym, 422 .sym = al->sym,
@@ -478,18 +425,19 @@ struct hist_entry *__hists__add_entry(struct hists *self,
478 .ip = al->addr, 425 .ip = al->addr,
479 .level = al->level, 426 .level = al->level,
480 .stat = { 427 .stat = {
481 .period = period,
482 .nr_events = 1, 428 .nr_events = 1,
429 .period = period,
483 .weight = weight, 430 .weight = weight,
484 }, 431 },
485 .parent = sym_parent, 432 .parent = sym_parent,
486 .filtered = symbol__parent_filter(sym_parent), 433 .filtered = symbol__parent_filter(sym_parent),
487 .hists = self, 434 .hists = hists,
488 .branch_info = NULL, 435 .branch_info = bi,
489 .mem_info = NULL, 436 .mem_info = mi,
437 .transaction = transaction,
490 }; 438 };
491 439
492 return add_hist_entry(self, &entry, al, period, weight); 440 return add_hist_entry(hists, &entry, al, period, weight);
493} 441}
494 442
495int64_t 443int64_t
@@ -530,6 +478,7 @@ void hist_entry__free(struct hist_entry *he)
530{ 478{
531 free(he->branch_info); 479 free(he->branch_info);
532 free(he->mem_info); 480 free(he->mem_info);
481 free_srcline(he->srcline);
533 free(he); 482 free(he);
534} 483}
535 484
@@ -598,7 +547,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
598 hists__filter_entry_by_symbol(hists, he); 547 hists__filter_entry_by_symbol(hists, he);
599} 548}
600 549
601void hists__collapse_resort(struct hists *hists) 550void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
602{ 551{
603 struct rb_root *root; 552 struct rb_root *root;
604 struct rb_node *next; 553 struct rb_node *next;
@@ -625,6 +574,8 @@ void hists__collapse_resort(struct hists *hists)
625 */ 574 */
626 hists__apply_filters(hists, n); 575 hists__apply_filters(hists, n);
627 } 576 }
577 if (prog)
578 ui_progress__update(prog, 1);
628 } 579 }
629} 580}
630 581
@@ -884,7 +835,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
884 struct rb_node **p; 835 struct rb_node **p;
885 struct rb_node *parent = NULL; 836 struct rb_node *parent = NULL;
886 struct hist_entry *he; 837 struct hist_entry *he;
887 int cmp; 838 int64_t cmp;
888 839
889 if (sort__need_collapse) 840 if (sort__need_collapse)
890 root = &hists->entries_collapsed; 841 root = &hists->entries_collapsed;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 1329b6b6ffe6..b621347a1585 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -5,6 +5,8 @@
5#include <pthread.h> 5#include <pthread.h>
6#include "callchain.h" 6#include "callchain.h"
7#include "header.h" 7#include "header.h"
8#include "color.h"
9#include "ui/progress.h"
8 10
9extern struct callchain_param callchain_param; 11extern struct callchain_param callchain_param;
10 12
@@ -45,6 +47,8 @@ enum hist_column {
45 HISTC_CPU, 47 HISTC_CPU,
46 HISTC_SRCLINE, 48 HISTC_SRCLINE,
47 HISTC_MISPREDICT, 49 HISTC_MISPREDICT,
50 HISTC_IN_TX,
51 HISTC_ABORT,
48 HISTC_SYMBOL_FROM, 52 HISTC_SYMBOL_FROM,
49 HISTC_SYMBOL_TO, 53 HISTC_SYMBOL_TO,
50 HISTC_DSO_FROM, 54 HISTC_DSO_FROM,
@@ -57,6 +61,7 @@ enum hist_column {
57 HISTC_MEM_TLB, 61 HISTC_MEM_TLB,
58 HISTC_MEM_LVL, 62 HISTC_MEM_LVL,
59 HISTC_MEM_SNOOP, 63 HISTC_MEM_SNOOP,
64 HISTC_TRANSACTION,
60 HISTC_NR_COLS, /* Last entry */ 65 HISTC_NR_COLS, /* Last entry */
61}; 66};
62 67
@@ -79,54 +84,43 @@ struct hists {
79 u16 col_len[HISTC_NR_COLS]; 84 u16 col_len[HISTC_NR_COLS];
80}; 85};
81 86
82struct hist_entry *__hists__add_entry(struct hists *self, 87struct hist_entry *__hists__add_entry(struct hists *hists,
83 struct addr_location *al, 88 struct addr_location *al,
84 struct symbol *parent, u64 period, 89 struct symbol *parent,
85 u64 weight); 90 struct branch_info *bi,
91 struct mem_info *mi, u64 period,
92 u64 weight, u64 transaction);
86int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 93int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
87int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 94int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
88int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, 95int hist_entry__transaction_len(void);
96int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
89 struct hists *hists); 97 struct hists *hists);
90void hist_entry__free(struct hist_entry *); 98void hist_entry__free(struct hist_entry *);
91 99
92struct hist_entry *__hists__add_branch_entry(struct hists *self, 100void hists__output_resort(struct hists *hists);
93 struct addr_location *al, 101void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
94 struct symbol *sym_parent,
95 struct branch_info *bi,
96 u64 period,
97 u64 weight);
98
99struct hist_entry *__hists__add_mem_entry(struct hists *self,
100 struct addr_location *al,
101 struct symbol *sym_parent,
102 struct mem_info *mi,
103 u64 period,
104 u64 weight);
105
106void hists__output_resort(struct hists *self);
107void hists__collapse_resort(struct hists *self);
108 102
109void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 103void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
110void hists__output_recalc_col_len(struct hists *hists, int max_rows); 104void hists__output_recalc_col_len(struct hists *hists, int max_rows);
111 105
112void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); 106void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
113void hists__inc_nr_events(struct hists *self, u32 type); 107void hists__inc_nr_events(struct hists *hists, u32 type);
114void events_stats__inc(struct events_stats *stats, u32 type); 108void events_stats__inc(struct events_stats *stats, u32 type);
115size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 109size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
116 110
117size_t hists__fprintf(struct hists *self, bool show_header, int max_rows, 111size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
118 int max_cols, float min_pcnt, FILE *fp); 112 int max_cols, float min_pcnt, FILE *fp);
119 113
120int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); 114int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr);
121int hist_entry__annotate(struct hist_entry *self, size_t privsize); 115int hist_entry__annotate(struct hist_entry *he, size_t privsize);
122 116
123void hists__filter_by_dso(struct hists *hists); 117void hists__filter_by_dso(struct hists *hists);
124void hists__filter_by_thread(struct hists *hists); 118void hists__filter_by_thread(struct hists *hists);
125void hists__filter_by_symbol(struct hists *hists); 119void hists__filter_by_symbol(struct hists *hists);
126 120
127u16 hists__col_len(struct hists *self, enum hist_column col); 121u16 hists__col_len(struct hists *hists, enum hist_column col);
128void hists__set_col_len(struct hists *self, enum hist_column col, u16 len); 122void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len);
129bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); 123bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len);
130void hists__reset_col_len(struct hists *hists); 124void hists__reset_col_len(struct hists *hists);
131void hists__calc_col_len(struct hists *hists, struct hist_entry *he); 125void hists__calc_col_len(struct hists *hists, struct hist_entry *he);
132 126
@@ -175,6 +169,18 @@ void perf_hpp__init(void);
175void perf_hpp__column_register(struct perf_hpp_fmt *format); 169void perf_hpp__column_register(struct perf_hpp_fmt *format);
176void perf_hpp__column_enable(unsigned col); 170void perf_hpp__column_enable(unsigned col);
177 171
172static inline size_t perf_hpp__use_color(void)
173{
174 return !symbol_conf.field_sep;
175}
176
177static inline size_t perf_hpp__color_overhead(void)
178{
179 return perf_hpp__use_color() ?
180 (COLOR_MAXLEN + sizeof(PERF_COLOR_RESET)) * PERF_HPP__MAX_INDEX
181 : 0;
182}
183
178struct perf_evlist; 184struct perf_evlist;
179 185
180struct hist_browser_timer { 186struct hist_browser_timer {
@@ -183,7 +189,7 @@ struct hist_browser_timer {
183 int refresh; 189 int refresh;
184}; 190};
185 191
186#ifdef SLANG_SUPPORT 192#ifdef HAVE_SLANG_SUPPORT
187#include "../ui/keysyms.h" 193#include "../ui/keysyms.h"
188int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, 194int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
189 struct hist_browser_timer *hbt); 195 struct hist_browser_timer *hbt);
@@ -204,12 +210,9 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
204 return 0; 210 return 0;
205} 211}
206 212
207static inline int hist_entry__tui_annotate(struct hist_entry *self 213static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused,
208 __maybe_unused, 214 struct perf_evsel *evsel __maybe_unused,
209 struct perf_evsel *evsel 215 struct hist_browser_timer *hbt __maybe_unused)
210 __maybe_unused,
211 struct hist_browser_timer *hbt
212 __maybe_unused)
213{ 216{
214 return 0; 217 return 0;
215} 218}
@@ -224,20 +227,5 @@ static inline int script_browse(const char *script_opt __maybe_unused)
224#define K_SWITCH_INPUT_DATA -3000 227#define K_SWITCH_INPUT_DATA -3000
225#endif 228#endif
226 229
227#ifdef GTK2_SUPPORT 230unsigned int hists__sort_list_width(struct hists *hists);
228int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, const char *help,
229 struct hist_browser_timer *hbt __maybe_unused,
230 float min_pcnt);
231#else
232static inline
233int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
234 const char *help __maybe_unused,
235 struct hist_browser_timer *hbt __maybe_unused,
236 float min_pcnt __maybe_unused)
237{
238 return 0;
239}
240#endif
241
242unsigned int hists__sort_list_width(struct hists *self);
243#endif /* __PERF_HIST_H */ 231#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h
index cf6727e99c44..8f149655f497 100644
--- a/tools/perf/util/include/dwarf-regs.h
+++ b/tools/perf/util/include/dwarf-regs.h
@@ -1,7 +1,7 @@
1#ifndef _PERF_DWARF_REGS_H_ 1#ifndef _PERF_DWARF_REGS_H_
2#define _PERF_DWARF_REGS_H_ 2#define _PERF_DWARF_REGS_H_
3 3
4#ifdef DWARF_SUPPORT 4#ifdef HAVE_DWARF_SUPPORT
5const char *get_arch_regstr(unsigned int n); 5const char *get_arch_regstr(unsigned int n);
6#endif 6#endif
7 7
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/perf/util/include/linux/compiler.h
index 96b919dae11c..b003ad7200b2 100644
--- a/tools/perf/util/include/linux/compiler.h
+++ b/tools/perf/util/include/linux/compiler.h
@@ -2,20 +2,29 @@
2#define _PERF_LINUX_COMPILER_H_ 2#define _PERF_LINUX_COMPILER_H_
3 3
4#ifndef __always_inline 4#ifndef __always_inline
5#define __always_inline inline 5# define __always_inline inline __attribute__((always_inline))
6#endif 6#endif
7
7#define __user 8#define __user
9
8#ifndef __attribute_const__ 10#ifndef __attribute_const__
9#define __attribute_const__ 11# define __attribute_const__
10#endif 12#endif
11 13
12#ifndef __maybe_unused 14#ifndef __maybe_unused
13#define __maybe_unused __attribute__((unused)) 15# define __maybe_unused __attribute__((unused))
16#endif
17
18#ifndef __packed
19# define __packed __attribute__((__packed__))
14#endif 20#endif
15#define __packed __attribute__((__packed__))
16 21
17#ifndef __force 22#ifndef __force
18#define __force 23# define __force
24#endif
25
26#ifndef __weak
27# define __weak __attribute__((weak))
19#endif 28#endif
20 29
21#endif 30#endif
diff --git a/tools/perf/util/include/linux/magic.h b/tools/perf/util/include/linux/magic.h
index 58b64ed4da12..07d63cf3e0f6 100644
--- a/tools/perf/util/include/linux/magic.h
+++ b/tools/perf/util/include/linux/magic.h
@@ -9,4 +9,8 @@
9#define SYSFS_MAGIC 0x62656572 9#define SYSFS_MAGIC 0x62656572
10#endif 10#endif
11 11
12#ifndef PROC_SUPER_MAGIC
13#define PROC_SUPER_MAGIC 0x9fa0
14#endif
15
12#endif 16#endif
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
index 11a8d86f7fea..89715b64a315 100644
--- a/tools/perf/util/intlist.c
+++ b/tools/perf/util/intlist.c
@@ -20,6 +20,7 @@ static struct rb_node *intlist__node_new(struct rblist *rblist __maybe_unused,
20 20
21 if (node != NULL) { 21 if (node != NULL) {
22 node->i = i; 22 node->i = i;
23 node->priv = NULL;
23 rc = &node->rb_node; 24 rc = &node->rb_node;
24 } 25 }
25 26
@@ -57,22 +58,36 @@ void intlist__remove(struct intlist *ilist, struct int_node *node)
57 rblist__remove_node(&ilist->rblist, &node->rb_node); 58 rblist__remove_node(&ilist->rblist, &node->rb_node);
58} 59}
59 60
60struct int_node *intlist__find(struct intlist *ilist, int i) 61static struct int_node *__intlist__findnew(struct intlist *ilist,
62 int i, bool create)
61{ 63{
62 struct int_node *node; 64 struct int_node *node = NULL;
63 struct rb_node *rb_node; 65 struct rb_node *rb_node;
64 66
65 if (ilist == NULL) 67 if (ilist == NULL)
66 return NULL; 68 return NULL;
67 69
68 node = NULL; 70 if (create)
69 rb_node = rblist__find(&ilist->rblist, (void *)((long)i)); 71 rb_node = rblist__findnew(&ilist->rblist, (void *)((long)i));
72 else
73 rb_node = rblist__find(&ilist->rblist, (void *)((long)i));
74
70 if (rb_node) 75 if (rb_node)
71 node = container_of(rb_node, struct int_node, rb_node); 76 node = container_of(rb_node, struct int_node, rb_node);
72 77
73 return node; 78 return node;
74} 79}
75 80
81struct int_node *intlist__find(struct intlist *ilist, int i)
82{
83 return __intlist__findnew(ilist, i, false);
84}
85
86struct int_node *intlist__findnew(struct intlist *ilist, int i)
87{
88 return __intlist__findnew(ilist, i, true);
89}
90
76static int intlist__parse_list(struct intlist *ilist, const char *s) 91static int intlist__parse_list(struct intlist *ilist, const char *s)
77{ 92{
78 char *sep; 93 char *sep;
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
index 62351dad848f..aa6877d36858 100644
--- a/tools/perf/util/intlist.h
+++ b/tools/perf/util/intlist.h
@@ -9,6 +9,7 @@
9struct int_node { 9struct int_node {
10 struct rb_node rb_node; 10 struct rb_node rb_node;
11 int i; 11 int i;
12 void *priv;
12}; 13};
13 14
14struct intlist { 15struct intlist {
@@ -23,6 +24,7 @@ int intlist__add(struct intlist *ilist, int i);
23 24
24struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx); 25struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx);
25struct int_node *intlist__find(struct intlist *ilist, int i); 26struct int_node *intlist__find(struct intlist *ilist, int i);
27struct int_node *intlist__findnew(struct intlist *ilist, int i);
26 28
27static inline bool intlist__has_entry(struct intlist *ilist, int i) 29static inline bool intlist__has_entry(struct intlist *ilist, int i)
28{ 30{
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 6188d2876a71..84cdb072ac83 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -40,12 +40,29 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
40 return -ENOMEM; 40 return -ENOMEM;
41 41
42 snprintf(comm, sizeof(comm), "[guest/%d]", pid); 42 snprintf(comm, sizeof(comm), "[guest/%d]", pid);
43 thread__set_comm(thread, comm); 43 thread__set_comm(thread, comm, 0);
44 } 44 }
45 45
46 return 0; 46 return 0;
47} 47}
48 48
49struct machine *machine__new_host(void)
50{
51 struct machine *machine = malloc(sizeof(*machine));
52
53 if (machine != NULL) {
54 machine__init(machine, "", HOST_KERNEL_ID);
55
56 if (machine__create_kernel_maps(machine) < 0)
57 goto out_delete;
58 }
59
60 return machine;
61out_delete:
62 free(machine);
63 return NULL;
64}
65
49static void dsos__delete(struct list_head *dsos) 66static void dsos__delete(struct list_head *dsos)
50{ 67{
51 struct dso *pos, *n; 68 struct dso *pos, *n;
@@ -314,7 +331,8 @@ struct thread *machine__find_thread(struct machine *machine, pid_t tid)
314 return __machine__findnew_thread(machine, 0, tid, false); 331 return __machine__findnew_thread(machine, 0, tid, false);
315} 332}
316 333
317int machine__process_comm_event(struct machine *machine, union perf_event *event) 334int machine__process_comm_event(struct machine *machine, union perf_event *event,
335 struct perf_sample *sample)
318{ 336{
319 struct thread *thread = machine__findnew_thread(machine, 337 struct thread *thread = machine__findnew_thread(machine,
320 event->comm.pid, 338 event->comm.pid,
@@ -323,7 +341,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
323 if (dump_trace) 341 if (dump_trace)
324 perf_event__fprintf_comm(event, stdout); 342 perf_event__fprintf_comm(event, stdout);
325 343
326 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { 344 if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) {
327 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 345 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
328 return -1; 346 return -1;
329 } 347 }
@@ -332,7 +350,7 @@ int machine__process_comm_event(struct machine *machine, union perf_event *event
332} 350}
333 351
334int machine__process_lost_event(struct machine *machine __maybe_unused, 352int machine__process_lost_event(struct machine *machine __maybe_unused,
335 union perf_event *event) 353 union perf_event *event, struct perf_sample *sample __maybe_unused)
336{ 354{
337 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", 355 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
338 event->lost.id, event->lost.lost); 356 event->lost.id, event->lost.lost);
@@ -776,75 +794,44 @@ static int machine__set_modules_path(struct machine *machine)
776 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); 794 return map_groups__set_modules_path_dir(&machine->kmaps, modules_path);
777} 795}
778 796
779static int machine__create_modules(struct machine *machine) 797static int machine__create_module(void *arg, const char *name, u64 start)
780{ 798{
781 char *line = NULL; 799 struct machine *machine = arg;
782 size_t n;
783 FILE *file;
784 struct map *map; 800 struct map *map;
801
802 map = machine__new_module(machine, start, name);
803 if (map == NULL)
804 return -1;
805
806 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
807
808 return 0;
809}
810
811static int machine__create_modules(struct machine *machine)
812{
785 const char *modules; 813 const char *modules;
786 char path[PATH_MAX]; 814 char path[PATH_MAX];
787 815
788 if (machine__is_default_guest(machine)) 816 if (machine__is_default_guest(machine)) {
789 modules = symbol_conf.default_guest_modules; 817 modules = symbol_conf.default_guest_modules;
790 else { 818 } else {
791 sprintf(path, "%s/proc/modules", machine->root_dir); 819 snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir);
792 modules = path; 820 modules = path;
793 } 821 }
794 822
795 if (symbol__restricted_filename(modules, "/proc/modules")) 823 if (symbol__restricted_filename(modules, "/proc/modules"))
796 return -1; 824 return -1;
797 825
798 file = fopen(modules, "r"); 826 if (modules__parse(modules, machine, machine__create_module))
799 if (file == NULL)
800 return -1; 827 return -1;
801 828
802 while (!feof(file)) { 829 if (!machine__set_modules_path(machine))
803 char name[PATH_MAX]; 830 return 0;
804 u64 start;
805 char *sep;
806 int line_len;
807
808 line_len = getline(&line, &n, file);
809 if (line_len < 0)
810 break;
811
812 if (!line)
813 goto out_failure;
814
815 line[--line_len] = '\0'; /* \n */
816
817 sep = strrchr(line, 'x');
818 if (sep == NULL)
819 continue;
820
821 hex2u64(sep + 1, &start);
822
823 sep = strchr(line, ' ');
824 if (sep == NULL)
825 continue;
826
827 *sep = '\0';
828
829 snprintf(name, sizeof(name), "[%s]", line);
830 map = machine__new_module(machine, start, name);
831 if (map == NULL)
832 goto out_delete_line;
833 dso__kernel_module_get_build_id(map->dso, machine->root_dir);
834 }
835 831
836 free(line); 832 pr_debug("Problems setting modules path maps, continuing anyway...\n");
837 fclose(file);
838 833
839 if (machine__set_modules_path(machine) < 0) {
840 pr_debug("Problems setting modules path maps, continuing anyway...\n");
841 }
842 return 0; 834 return 0;
843
844out_delete_line:
845 free(line);
846out_failure:
847 return -1;
848} 835}
849 836
850int machine__create_kernel_maps(struct machine *machine) 837int machine__create_kernel_maps(struct machine *machine)
@@ -998,7 +985,8 @@ out_problem:
998} 985}
999 986
1000int machine__process_mmap2_event(struct machine *machine, 987int machine__process_mmap2_event(struct machine *machine,
1001 union perf_event *event) 988 union perf_event *event,
989 struct perf_sample *sample __maybe_unused)
1002{ 990{
1003 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 991 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1004 struct thread *thread; 992 struct thread *thread;
@@ -1045,7 +1033,8 @@ out_problem:
1045 return 0; 1033 return 0;
1046} 1034}
1047 1035
1048int machine__process_mmap_event(struct machine *machine, union perf_event *event) 1036int machine__process_mmap_event(struct machine *machine, union perf_event *event,
1037 struct perf_sample *sample __maybe_unused)
1049{ 1038{
1050 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1039 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1051 struct thread *thread; 1040 struct thread *thread;
@@ -1102,7 +1091,8 @@ static void machine__remove_thread(struct machine *machine, struct thread *th)
1102 list_add_tail(&th->node, &machine->dead_threads); 1091 list_add_tail(&th->node, &machine->dead_threads);
1103} 1092}
1104 1093
1105int machine__process_fork_event(struct machine *machine, union perf_event *event) 1094int machine__process_fork_event(struct machine *machine, union perf_event *event,
1095 struct perf_sample *sample)
1106{ 1096{
1107 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1097 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1108 struct thread *parent = machine__findnew_thread(machine, 1098 struct thread *parent = machine__findnew_thread(machine,
@@ -1119,7 +1109,7 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1119 perf_event__fprintf_task(event, stdout); 1109 perf_event__fprintf_task(event, stdout);
1120 1110
1121 if (thread == NULL || parent == NULL || 1111 if (thread == NULL || parent == NULL ||
1122 thread__fork(thread, parent) < 0) { 1112 thread__fork(thread, parent, sample->time) < 0) {
1123 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); 1113 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1124 return -1; 1114 return -1;
1125 } 1115 }
@@ -1127,8 +1117,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event
1127 return 0; 1117 return 0;
1128} 1118}
1129 1119
1130int machine__process_exit_event(struct machine *machine __maybe_unused, 1120int machine__process_exit_event(struct machine *machine, union perf_event *event,
1131 union perf_event *event) 1121 struct perf_sample *sample __maybe_unused)
1132{ 1122{
1133 struct thread *thread = machine__find_thread(machine, event->fork.tid); 1123 struct thread *thread = machine__find_thread(machine, event->fork.tid);
1134 1124
@@ -1141,23 +1131,24 @@ int machine__process_exit_event(struct machine *machine __maybe_unused,
1141 return 0; 1131 return 0;
1142} 1132}
1143 1133
1144int machine__process_event(struct machine *machine, union perf_event *event) 1134int machine__process_event(struct machine *machine, union perf_event *event,
1135 struct perf_sample *sample)
1145{ 1136{
1146 int ret; 1137 int ret;
1147 1138
1148 switch (event->header.type) { 1139 switch (event->header.type) {
1149 case PERF_RECORD_COMM: 1140 case PERF_RECORD_COMM:
1150 ret = machine__process_comm_event(machine, event); break; 1141 ret = machine__process_comm_event(machine, event, sample); break;
1151 case PERF_RECORD_MMAP: 1142 case PERF_RECORD_MMAP:
1152 ret = machine__process_mmap_event(machine, event); break; 1143 ret = machine__process_mmap_event(machine, event, sample); break;
1153 case PERF_RECORD_MMAP2: 1144 case PERF_RECORD_MMAP2:
1154 ret = machine__process_mmap2_event(machine, event); break; 1145 ret = machine__process_mmap2_event(machine, event, sample); break;
1155 case PERF_RECORD_FORK: 1146 case PERF_RECORD_FORK:
1156 ret = machine__process_fork_event(machine, event); break; 1147 ret = machine__process_fork_event(machine, event, sample); break;
1157 case PERF_RECORD_EXIT: 1148 case PERF_RECORD_EXIT:
1158 ret = machine__process_exit_event(machine, event); break; 1149 ret = machine__process_exit_event(machine, event, sample); break;
1159 case PERF_RECORD_LOST: 1150 case PERF_RECORD_LOST:
1160 ret = machine__process_lost_event(machine, event); break; 1151 ret = machine__process_lost_event(machine, event, sample); break;
1161 default: 1152 default:
1162 ret = -1; 1153 ret = -1;
1163 break; 1154 break;
@@ -1267,10 +1258,12 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1267 struct thread *thread, 1258 struct thread *thread,
1268 struct ip_callchain *chain, 1259 struct ip_callchain *chain,
1269 struct symbol **parent, 1260 struct symbol **parent,
1270 struct addr_location *root_al) 1261 struct addr_location *root_al,
1262 int max_stack)
1271{ 1263{
1272 u8 cpumode = PERF_RECORD_MISC_USER; 1264 u8 cpumode = PERF_RECORD_MISC_USER;
1273 unsigned int i; 1265 int chain_nr = min(max_stack, (int)chain->nr);
1266 int i;
1274 int err; 1267 int err;
1275 1268
1276 callchain_cursor_reset(&callchain_cursor); 1269 callchain_cursor_reset(&callchain_cursor);
@@ -1280,7 +1273,7 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1280 return 0; 1273 return 0;
1281 } 1274 }
1282 1275
1283 for (i = 0; i < chain->nr; i++) { 1276 for (i = 0; i < chain_nr; i++) {
1284 u64 ip; 1277 u64 ip;
1285 struct addr_location al; 1278 struct addr_location al;
1286 1279
@@ -1352,12 +1345,14 @@ int machine__resolve_callchain(struct machine *machine,
1352 struct thread *thread, 1345 struct thread *thread,
1353 struct perf_sample *sample, 1346 struct perf_sample *sample,
1354 struct symbol **parent, 1347 struct symbol **parent,
1355 struct addr_location *root_al) 1348 struct addr_location *root_al,
1349 int max_stack)
1356{ 1350{
1357 int ret; 1351 int ret;
1358 1352
1359 ret = machine__resolve_callchain_sample(machine, thread, 1353 ret = machine__resolve_callchain_sample(machine, thread,
1360 sample->callchain, parent, root_al); 1354 sample->callchain, parent,
1355 root_al, max_stack);
1361 if (ret) 1356 if (ret)
1362 return ret; 1357 return ret;
1363 1358
@@ -1373,6 +1368,41 @@ int machine__resolve_callchain(struct machine *machine,
1373 1368
1374 return unwind__get_entries(unwind_entry, &callchain_cursor, machine, 1369 return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
1375 thread, evsel->attr.sample_regs_user, 1370 thread, evsel->attr.sample_regs_user,
1376 sample); 1371 sample, max_stack);
1377 1372
1378} 1373}
1374
1375int machine__for_each_thread(struct machine *machine,
1376 int (*fn)(struct thread *thread, void *p),
1377 void *priv)
1378{
1379 struct rb_node *nd;
1380 struct thread *thread;
1381 int rc = 0;
1382
1383 for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) {
1384 thread = rb_entry(nd, struct thread, rb_node);
1385 rc = fn(thread, priv);
1386 if (rc != 0)
1387 return rc;
1388 }
1389
1390 list_for_each_entry(thread, &machine->dead_threads, node) {
1391 rc = fn(thread, priv);
1392 if (rc != 0)
1393 return rc;
1394 }
1395 return rc;
1396}
1397
1398int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
1399 struct target *target, struct thread_map *threads,
1400 perf_event__handler_t process, bool data_mmap)
1401{
1402 if (target__has_task(target))
1403 return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap);
1404 else if (target__has_cpu(target))
1405 return perf_event__synthesize_threads(tool, process, machine, data_mmap);
1406 /* command specified */
1407 return 0;
1408}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 58a6be1fc739..477133015440 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -4,6 +4,7 @@
4#include <sys/types.h> 4#include <sys/types.h>
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include "map.h" 6#include "map.h"
7#include "event.h"
7 8
8struct addr_location; 9struct addr_location;
9struct branch_stack; 10struct branch_stack;
@@ -40,13 +41,20 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
40 41
41struct thread *machine__find_thread(struct machine *machine, pid_t tid); 42struct thread *machine__find_thread(struct machine *machine, pid_t tid);
42 43
43int machine__process_comm_event(struct machine *machine, union perf_event *event); 44int machine__process_comm_event(struct machine *machine, union perf_event *event,
44int machine__process_exit_event(struct machine *machine, union perf_event *event); 45 struct perf_sample *sample);
45int machine__process_fork_event(struct machine *machine, union perf_event *event); 46int machine__process_exit_event(struct machine *machine, union perf_event *event,
46int machine__process_lost_event(struct machine *machine, union perf_event *event); 47 struct perf_sample *sample);
47int machine__process_mmap_event(struct machine *machine, union perf_event *event); 48int machine__process_fork_event(struct machine *machine, union perf_event *event,
48int machine__process_mmap2_event(struct machine *machine, union perf_event *event); 49 struct perf_sample *sample);
49int machine__process_event(struct machine *machine, union perf_event *event); 50int machine__process_lost_event(struct machine *machine, union perf_event *event,
51 struct perf_sample *sample);
52int machine__process_mmap_event(struct machine *machine, union perf_event *event,
53 struct perf_sample *sample);
54int machine__process_mmap2_event(struct machine *machine, union perf_event *event,
55 struct perf_sample *sample);
56int machine__process_event(struct machine *machine, union perf_event *event,
57 struct perf_sample *sample);
50 58
51typedef void (*machine__process_t)(struct machine *machine, void *data); 59typedef void (*machine__process_t)(struct machine *machine, void *data);
52 60
@@ -74,6 +82,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size);
74void machines__set_symbol_filter(struct machines *machines, 82void machines__set_symbol_filter(struct machines *machines,
75 symbol_filter_t symbol_filter); 83 symbol_filter_t symbol_filter);
76 84
85struct machine *machine__new_host(void);
77int machine__init(struct machine *machine, const char *root_dir, pid_t pid); 86int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
78void machine__exit(struct machine *machine); 87void machine__exit(struct machine *machine);
79void machine__delete_dead_threads(struct machine *machine); 88void machine__delete_dead_threads(struct machine *machine);
@@ -91,7 +100,8 @@ int machine__resolve_callchain(struct machine *machine,
91 struct thread *thread, 100 struct thread *thread,
92 struct perf_sample *sample, 101 struct perf_sample *sample,
93 struct symbol **parent, 102 struct symbol **parent,
94 struct addr_location *root_al); 103 struct addr_location *root_al,
104 int max_stack);
95 105
96/* 106/*
97 * Default guest kernel is defined by parameter --guestkallsyms 107 * Default guest kernel is defined by parameter --guestkallsyms
@@ -165,4 +175,19 @@ void machines__destroy_kernel_maps(struct machines *machines);
165 175
166size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); 176size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp);
167 177
178int machine__for_each_thread(struct machine *machine,
179 int (*fn)(struct thread *thread, void *p),
180 void *priv);
181
182int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
183 struct target *target, struct thread_map *threads,
184 perf_event__handler_t process, bool data_mmap);
185static inline
186int machine__synthesize_threads(struct machine *machine, struct target *target,
187 struct thread_map *threads, bool data_mmap)
188{
189 return __machine__synthesize_threads(machine, NULL, target, threads,
190 perf_event__process, data_mmap);
191}
192
168#endif /* __PERF_MACHINE_H */ 193#endif /* __PERF_MACHINE_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 4f6680d2043b..ef5bc913ca7a 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -172,7 +172,7 @@ int map__load(struct map *map, symbol_filter_t filter)
172 pr_warning(", continuing without symbols\n"); 172 pr_warning(", continuing without symbols\n");
173 return -1; 173 return -1;
174 } else if (nr == 0) { 174 } else if (nr == 0) {
175#ifdef LIBELF_SUPPORT 175#ifdef HAVE_LIBELF_SUPPORT
176 const size_t len = strlen(name); 176 const size_t len = strlen(name);
177 const size_t real_len = len - sizeof(DSO__DELETED); 177 const size_t real_len = len - sizeof(DSO__DELETED);
178 178
@@ -252,10 +252,16 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
252 return fprintf(fp, "%s", dsoname); 252 return fprintf(fp, "%s", dsoname);
253} 253}
254 254
255/* 255/**
256 * map__rip_2objdump - convert symbol start address to objdump address.
257 * @map: memory map
258 * @rip: symbol start address
259 *
256 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 260 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
257 * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is 261 * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
258 * relative to section start. 262 * relative to section start.
263 *
264 * Return: Address suitable for passing to "objdump --start-address="
259 */ 265 */
260u64 map__rip_2objdump(struct map *map, u64 rip) 266u64 map__rip_2objdump(struct map *map, u64 rip)
261{ 267{
@@ -268,6 +274,29 @@ u64 map__rip_2objdump(struct map *map, u64 rip)
268 return map->unmap_ip(map, rip); 274 return map->unmap_ip(map, rip);
269} 275}
270 276
277/**
278 * map__objdump_2mem - convert objdump address to a memory address.
279 * @map: memory map
280 * @ip: objdump address
281 *
282 * Closely related to map__rip_2objdump(), this function takes an address from
283 * objdump and converts it to a memory address. Note this assumes that @map
284 * contains the address. To be sure the result is valid, check it forwards
285 * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip
286 *
287 * Return: Memory address.
288 */
289u64 map__objdump_2mem(struct map *map, u64 ip)
290{
291 if (!map->dso->adjust_symbols)
292 return map->unmap_ip(map, ip);
293
294 if (map->dso->rel)
295 return map->unmap_ip(map, ip + map->pgoff);
296
297 return ip;
298}
299
271void map_groups__init(struct map_groups *mg) 300void map_groups__init(struct map_groups *mg)
272{ 301{
273 int i; 302 int i;
@@ -371,6 +400,23 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
371 return NULL; 400 return NULL;
372} 401}
373 402
403int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
404{
405 if (ams->addr < ams->map->start || ams->addr > ams->map->end) {
406 if (ams->map->groups == NULL)
407 return -1;
408 ams->map = map_groups__find(ams->map->groups, ams->map->type,
409 ams->addr);
410 if (ams->map == NULL)
411 return -1;
412 }
413
414 ams->al_addr = ams->map->map_ip(ams->map, ams->addr);
415 ams->sym = map__find_symbol(ams->map, ams->al_addr, filter);
416
417 return ams->sym ? 0 : -1;
418}
419
374size_t __map_groups__fprintf_maps(struct map_groups *mg, 420size_t __map_groups__fprintf_maps(struct map_groups *mg,
375 enum map_type type, int verbose, FILE *fp) 421 enum map_type type, int verbose, FILE *fp)
376{ 422{
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 4886ca280536..e4e259c3ba16 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -84,6 +84,9 @@ static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip)
84/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */ 84/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
85u64 map__rip_2objdump(struct map *map, u64 rip); 85u64 map__rip_2objdump(struct map *map, u64 rip);
86 86
87/* objdump address -> memory address */
88u64 map__objdump_2mem(struct map *map, u64 ip);
89
87struct symbol; 90struct symbol;
88 91
89typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 92typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
@@ -167,6 +170,10 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
167 struct map **mapp, 170 struct map **mapp,
168 symbol_filter_t filter); 171 symbol_filter_t filter);
169 172
173struct addr_map_symbol;
174
175int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter);
176
170static inline 177static inline
171struct symbol *map_groups__find_function_by_name(struct map_groups *mg, 178struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
172 const char *name, struct map **mapp, 179 const char *name, struct map **mapp,
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 98125319b158..6de6f89c2a61 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -277,7 +277,7 @@ static int __add_event(struct list_head *list, int *idx,
277 277
278 event_attr_init(attr); 278 event_attr_init(attr);
279 279
280 evsel = perf_evsel__new(attr, (*idx)++); 280 evsel = perf_evsel__new_idx(attr, (*idx)++);
281 if (!evsel) 281 if (!evsel)
282 return -ENOMEM; 282 return -ENOMEM;
283 283
@@ -378,7 +378,7 @@ static int add_tracepoint(struct list_head *list, int *idx,
378{ 378{
379 struct perf_evsel *evsel; 379 struct perf_evsel *evsel;
380 380
381 evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); 381 evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++);
382 if (!evsel) 382 if (!evsel)
383 return -ENOMEM; 383 return -ENOMEM;
384 384
@@ -998,8 +998,10 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
998 char evt_path[MAXPATHLEN]; 998 char evt_path[MAXPATHLEN];
999 char dir_path[MAXPATHLEN]; 999 char dir_path[MAXPATHLEN];
1000 1000
1001 if (debugfs_valid_mountpoint(tracing_events_path)) 1001 if (debugfs_valid_mountpoint(tracing_events_path)) {
1002 printf(" [ Tracepoints not available: %s ]\n", strerror(errno));
1002 return; 1003 return;
1004 }
1003 1005
1004 sys_dir = opendir(tracing_events_path); 1006 sys_dir = opendir(tracing_events_path);
1005 if (!sys_dir) 1007 if (!sys_dir)
@@ -1095,7 +1097,7 @@ static bool is_event_supported(u8 type, unsigned config)
1095 .threads = { 0 }, 1097 .threads = { 0 },
1096 }; 1098 };
1097 1099
1098 evsel = perf_evsel__new(&attr, 0); 1100 evsel = perf_evsel__new(&attr);
1099 if (evsel) { 1101 if (evsel) {
1100 ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; 1102 ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
1101 perf_evsel__delete(evsel); 1103 perf_evsel__delete(evsel);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 91346b753960..343299575b30 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -126,6 +126,37 @@ modifier_bp [rwx]{1,3}
126 126
127} 127}
128 128
129<config>{
130config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
131config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
132config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
133name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
134period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
135branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
136, { return ','; }
137"/" { BEGIN(INITIAL); return '/'; }
138{name_minus} { return str(yyscanner, PE_NAME); }
139}
140
141<mem>{
142{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
143: { return ':'; }
144{num_dec} { return value(yyscanner, 10); }
145{num_hex} { return value(yyscanner, 16); }
146 /*
147 * We need to separate 'mem:' scanner part, in order to get specific
148 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
149 * and we'd need to parse it manually. During the escape from <mem>
150 * state we need to put the escaping char back, so we dont miss it.
151 */
152. { unput(*yytext); BEGIN(INITIAL); }
153 /*
154 * We destroy the scanner after reaching EOF,
155 * but anyway just to be sure get back to INIT state.
156 */
157<<EOF>> { BEGIN(INITIAL); }
158}
159
129cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } 160cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
130stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } 161stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
131stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } 162stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
@@ -162,18 +193,6 @@ speculative-read|speculative-load |
162refs|Reference|ops|access | 193refs|Reference|ops|access |
163misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } 194misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); }
164 195
165<config>{
166config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
167config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
168config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
169name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
170period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
171branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
172, { return ','; }
173"/" { BEGIN(INITIAL); return '/'; }
174{name_minus} { return str(yyscanner, PE_NAME); }
175}
176
177mem: { BEGIN(mem); return PE_PREFIX_MEM; } 196mem: { BEGIN(mem); return PE_PREFIX_MEM; }
178r{num_raw_hex} { return raw(yyscanner); } 197r{num_raw_hex} { return raw(yyscanner); }
179{num_dec} { return value(yyscanner, 10); } 198{num_dec} { return value(yyscanner, 10); }
@@ -189,25 +208,7 @@ r{num_raw_hex} { return raw(yyscanner); }
189"}" { return '}'; } 208"}" { return '}'; }
190= { return '='; } 209= { return '='; }
191\n { } 210\n { }
192 211. { }
193<mem>{
194{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
195: { return ':'; }
196{num_dec} { return value(yyscanner, 10); }
197{num_hex} { return value(yyscanner, 16); }
198 /*
199 * We need to separate 'mem:' scanner part, in order to get specific
200 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
201 * and we'd need to parse it manually. During the escape from <mem>
202 * state we need to put the escaping char back, so we dont miss it.
203 */
204. { unput(*yytext); BEGIN(INITIAL); }
205 /*
206 * We destroy the scanner after reaching EOF,
207 * but anyway just to be sure get back to INIT state.
208 */
209<<EOF>> { BEGIN(INITIAL); }
210}
211 212
212%% 213%%
213 214
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 2bc9e70df7e2..31f404a032a9 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -339,10 +339,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
339 if (arg[1] != '-') { 339 if (arg[1] != '-') {
340 ctx->opt = arg + 1; 340 ctx->opt = arg + 1;
341 if (internal_help && *ctx->opt == 'h') 341 if (internal_help && *ctx->opt == 'h')
342 return parse_options_usage(usagestr, options); 342 return usage_with_options_internal(usagestr, options, 0);
343 switch (parse_short_opt(ctx, options)) { 343 switch (parse_short_opt(ctx, options)) {
344 case -1: 344 case -1:
345 return parse_options_usage(usagestr, options); 345 return parse_options_usage(usagestr, options, arg + 1, 1);
346 case -2: 346 case -2:
347 goto unknown; 347 goto unknown;
348 default: 348 default:
@@ -352,10 +352,11 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
352 check_typos(arg + 1, options); 352 check_typos(arg + 1, options);
353 while (ctx->opt) { 353 while (ctx->opt) {
354 if (internal_help && *ctx->opt == 'h') 354 if (internal_help && *ctx->opt == 'h')
355 return parse_options_usage(usagestr, options); 355 return usage_with_options_internal(usagestr, options, 0);
356 arg = ctx->opt;
356 switch (parse_short_opt(ctx, options)) { 357 switch (parse_short_opt(ctx, options)) {
357 case -1: 358 case -1:
358 return parse_options_usage(usagestr, options); 359 return parse_options_usage(usagestr, options, arg, 1);
359 case -2: 360 case -2:
360 /* fake a short option thing to hide the fact that we may have 361 /* fake a short option thing to hide the fact that we may have
361 * started to parse aggregated stuff 362 * started to parse aggregated stuff
@@ -383,12 +384,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
383 if (internal_help && !strcmp(arg + 2, "help-all")) 384 if (internal_help && !strcmp(arg + 2, "help-all"))
384 return usage_with_options_internal(usagestr, options, 1); 385 return usage_with_options_internal(usagestr, options, 1);
385 if (internal_help && !strcmp(arg + 2, "help")) 386 if (internal_help && !strcmp(arg + 2, "help"))
386 return parse_options_usage(usagestr, options); 387 return usage_with_options_internal(usagestr, options, 0);
387 if (!strcmp(arg + 2, "list-opts")) 388 if (!strcmp(arg + 2, "list-opts"))
388 return PARSE_OPT_LIST; 389 return PARSE_OPT_LIST;
389 switch (parse_long_opt(ctx, arg + 2, options)) { 390 switch (parse_long_opt(ctx, arg + 2, options)) {
390 case -1: 391 case -1:
391 return parse_options_usage(usagestr, options); 392 return parse_options_usage(usagestr, options, arg + 2, 0);
392 case -2: 393 case -2:
393 goto unknown; 394 goto unknown;
394 default: 395 default:
@@ -445,6 +446,89 @@ int parse_options(int argc, const char **argv, const struct option *options,
445#define USAGE_OPTS_WIDTH 24 446#define USAGE_OPTS_WIDTH 24
446#define USAGE_GAP 2 447#define USAGE_GAP 2
447 448
449static void print_option_help(const struct option *opts, int full)
450{
451 size_t pos;
452 int pad;
453
454 if (opts->type == OPTION_GROUP) {
455 fputc('\n', stderr);
456 if (*opts->help)
457 fprintf(stderr, "%s\n", opts->help);
458 return;
459 }
460 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
461 return;
462
463 pos = fprintf(stderr, " ");
464 if (opts->short_name)
465 pos += fprintf(stderr, "-%c", opts->short_name);
466 else
467 pos += fprintf(stderr, " ");
468
469 if (opts->long_name && opts->short_name)
470 pos += fprintf(stderr, ", ");
471 if (opts->long_name)
472 pos += fprintf(stderr, "--%s", opts->long_name);
473
474 switch (opts->type) {
475 case OPTION_ARGUMENT:
476 break;
477 case OPTION_LONG:
478 case OPTION_U64:
479 case OPTION_INTEGER:
480 case OPTION_UINTEGER:
481 if (opts->flags & PARSE_OPT_OPTARG)
482 if (opts->long_name)
483 pos += fprintf(stderr, "[=<n>]");
484 else
485 pos += fprintf(stderr, "[<n>]");
486 else
487 pos += fprintf(stderr, " <n>");
488 break;
489 case OPTION_CALLBACK:
490 if (opts->flags & PARSE_OPT_NOARG)
491 break;
492 /* FALLTHROUGH */
493 case OPTION_STRING:
494 if (opts->argh) {
495 if (opts->flags & PARSE_OPT_OPTARG)
496 if (opts->long_name)
497 pos += fprintf(stderr, "[=<%s>]", opts->argh);
498 else
499 pos += fprintf(stderr, "[<%s>]", opts->argh);
500 else
501 pos += fprintf(stderr, " <%s>", opts->argh);
502 } else {
503 if (opts->flags & PARSE_OPT_OPTARG)
504 if (opts->long_name)
505 pos += fprintf(stderr, "[=...]");
506 else
507 pos += fprintf(stderr, "[...]");
508 else
509 pos += fprintf(stderr, " ...");
510 }
511 break;
512 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
513 case OPTION_END:
514 case OPTION_GROUP:
515 case OPTION_BIT:
516 case OPTION_BOOLEAN:
517 case OPTION_INCR:
518 case OPTION_SET_UINT:
519 case OPTION_SET_PTR:
520 break;
521 }
522
523 if (pos <= USAGE_OPTS_WIDTH)
524 pad = USAGE_OPTS_WIDTH - pos;
525 else {
526 fputc('\n', stderr);
527 pad = USAGE_OPTS_WIDTH;
528 }
529 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
530}
531
448int usage_with_options_internal(const char * const *usagestr, 532int usage_with_options_internal(const char * const *usagestr,
449 const struct option *opts, int full) 533 const struct option *opts, int full)
450{ 534{
@@ -464,87 +548,9 @@ int usage_with_options_internal(const char * const *usagestr,
464 if (opts->type != OPTION_GROUP) 548 if (opts->type != OPTION_GROUP)
465 fputc('\n', stderr); 549 fputc('\n', stderr);
466 550
467 for (; opts->type != OPTION_END; opts++) { 551 for ( ; opts->type != OPTION_END; opts++)
468 size_t pos; 552 print_option_help(opts, full);
469 int pad;
470
471 if (opts->type == OPTION_GROUP) {
472 fputc('\n', stderr);
473 if (*opts->help)
474 fprintf(stderr, "%s\n", opts->help);
475 continue;
476 }
477 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
478 continue;
479
480 pos = fprintf(stderr, " ");
481 if (opts->short_name)
482 pos += fprintf(stderr, "-%c", opts->short_name);
483 else
484 pos += fprintf(stderr, " ");
485
486 if (opts->long_name && opts->short_name)
487 pos += fprintf(stderr, ", ");
488 if (opts->long_name)
489 pos += fprintf(stderr, "--%s", opts->long_name);
490
491 switch (opts->type) {
492 case OPTION_ARGUMENT:
493 break;
494 case OPTION_LONG:
495 case OPTION_U64:
496 case OPTION_INTEGER:
497 case OPTION_UINTEGER:
498 if (opts->flags & PARSE_OPT_OPTARG)
499 if (opts->long_name)
500 pos += fprintf(stderr, "[=<n>]");
501 else
502 pos += fprintf(stderr, "[<n>]");
503 else
504 pos += fprintf(stderr, " <n>");
505 break;
506 case OPTION_CALLBACK:
507 if (opts->flags & PARSE_OPT_NOARG)
508 break;
509 /* FALLTHROUGH */
510 case OPTION_STRING:
511 if (opts->argh) {
512 if (opts->flags & PARSE_OPT_OPTARG)
513 if (opts->long_name)
514 pos += fprintf(stderr, "[=<%s>]", opts->argh);
515 else
516 pos += fprintf(stderr, "[<%s>]", opts->argh);
517 else
518 pos += fprintf(stderr, " <%s>", opts->argh);
519 } else {
520 if (opts->flags & PARSE_OPT_OPTARG)
521 if (opts->long_name)
522 pos += fprintf(stderr, "[=...]");
523 else
524 pos += fprintf(stderr, "[...]");
525 else
526 pos += fprintf(stderr, " ...");
527 }
528 break;
529 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
530 case OPTION_END:
531 case OPTION_GROUP:
532 case OPTION_BIT:
533 case OPTION_BOOLEAN:
534 case OPTION_INCR:
535 case OPTION_SET_UINT:
536 case OPTION_SET_PTR:
537 break;
538 }
539 553
540 if (pos <= USAGE_OPTS_WIDTH)
541 pad = USAGE_OPTS_WIDTH - pos;
542 else {
543 fputc('\n', stderr);
544 pad = USAGE_OPTS_WIDTH;
545 }
546 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
547 }
548 fputc('\n', stderr); 554 fputc('\n', stderr);
549 555
550 return PARSE_OPT_HELP; 556 return PARSE_OPT_HELP;
@@ -559,9 +565,45 @@ void usage_with_options(const char * const *usagestr,
559} 565}
560 566
561int parse_options_usage(const char * const *usagestr, 567int parse_options_usage(const char * const *usagestr,
562 const struct option *opts) 568 const struct option *opts,
569 const char *optstr, bool short_opt)
563{ 570{
564 return usage_with_options_internal(usagestr, opts, 0); 571 if (!usagestr)
572 goto opt;
573
574 fprintf(stderr, "\n usage: %s\n", *usagestr++);
575 while (*usagestr && **usagestr)
576 fprintf(stderr, " or: %s\n", *usagestr++);
577 while (*usagestr) {
578 fprintf(stderr, "%s%s\n",
579 **usagestr ? " " : "",
580 *usagestr);
581 usagestr++;
582 }
583 fputc('\n', stderr);
584
585opt:
586 for ( ; opts->type != OPTION_END; opts++) {
587 if (short_opt) {
588 if (opts->short_name == *optstr)
589 break;
590 continue;
591 }
592
593 if (opts->long_name == NULL)
594 continue;
595
596 if (!prefixcmp(optstr, opts->long_name))
597 break;
598 if (!prefixcmp(optstr, "no-") &&
599 !prefixcmp(optstr + 3, opts->long_name))
600 break;
601 }
602
603 if (opts->type != OPTION_END)
604 print_option_help(opts, 0);
605
606 return PARSE_OPT_HELP;
565} 607}
566 608
567 609
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 7bb5999940ca..b0241e28eaf7 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -158,7 +158,9 @@ struct parse_opt_ctx_t {
158}; 158};
159 159
160extern int parse_options_usage(const char * const *usagestr, 160extern int parse_options_usage(const char * const *usagestr,
161 const struct option *opts); 161 const struct option *opts,
162 const char *optstr,
163 bool short_opt);
162 164
163extern void parse_options_start(struct parse_opt_ctx_t *ctx, 165extern void parse_options_start(struct parse_opt_ctx_t *ctx,
164 int argc, const char **argv, int flags); 166 int argc, const char **argv, int flags);
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index a8c49548ca48..5d13cb45b317 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -22,19 +22,23 @@ static const char *get_perf_dir(void)
22 return "."; 22 return ".";
23} 23}
24 24
25#ifndef HAVE_STRLCPY 25/*
26size_t strlcpy(char *dest, const char *src, size_t size) 26 * If libc has strlcpy() then that version will override this
27 * implementation:
28 */
29size_t __weak strlcpy(char *dest, const char *src, size_t size)
27{ 30{
28 size_t ret = strlen(src); 31 size_t ret = strlen(src);
29 32
30 if (size) { 33 if (size) {
31 size_t len = (ret >= size) ? size - 1 : ret; 34 size_t len = (ret >= size) ? size - 1 : ret;
35
32 memcpy(dest, src, len); 36 memcpy(dest, src, len);
33 dest[len] = '\0'; 37 dest[len] = '\0';
34 } 38 }
39
35 return ret; 40 return ret;
36} 41}
37#endif
38 42
39static char *get_pathname(void) 43static char *get_pathname(void)
40{ 44{
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index 5a4f2b6f3738..a3d42cd74919 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_REGS_H 1#ifndef __PERF_REGS_H
2#define __PERF_REGS_H 2#define __PERF_REGS_H
3 3
4#ifdef HAVE_PERF_REGS 4#ifdef HAVE_PERF_REGS_SUPPORT
5#include <perf_regs.h> 5#include <perf_regs.h>
6#else 6#else
7#define PERF_REGS_MASK 0 7#define PERF_REGS_MASK 0
@@ -10,5 +10,5 @@ static inline const char *perf_reg_name(int id __maybe_unused)
10{ 10{
11 return NULL; 11 return NULL;
12} 12}
13#endif /* HAVE_PERF_REGS */ 13#endif /* HAVE_PERF_REGS_SUPPORT */
14#endif /* __PERF_REGS_H */ 14#endif /* __PERF_REGS_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index bc9d8069d376..c232d8dd410b 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -4,7 +4,7 @@
4#include <unistd.h> 4#include <unistd.h>
5#include <stdio.h> 5#include <stdio.h>
6#include <dirent.h> 6#include <dirent.h>
7#include "sysfs.h" 7#include "fs.h"
8#include "util.h" 8#include "util.h"
9#include "pmu.h" 9#include "pmu.h"
10#include "parse-events.h" 10#include "parse-events.h"
@@ -77,9 +77,8 @@ static int pmu_format(const char *name, struct list_head *format)
77{ 77{
78 struct stat st; 78 struct stat st;
79 char path[PATH_MAX]; 79 char path[PATH_MAX];
80 const char *sysfs; 80 const char *sysfs = sysfs__mountpoint();
81 81
82 sysfs = sysfs_find_mountpoint();
83 if (!sysfs) 82 if (!sysfs)
84 return -1; 83 return -1;
85 84
@@ -166,9 +165,8 @@ static int pmu_aliases(const char *name, struct list_head *head)
166{ 165{
167 struct stat st; 166 struct stat st;
168 char path[PATH_MAX]; 167 char path[PATH_MAX];
169 const char *sysfs; 168 const char *sysfs = sysfs__mountpoint();
170 169
171 sysfs = sysfs_find_mountpoint();
172 if (!sysfs) 170 if (!sysfs)
173 return -1; 171 return -1;
174 172
@@ -212,11 +210,10 @@ static int pmu_type(const char *name, __u32 *type)
212{ 210{
213 struct stat st; 211 struct stat st;
214 char path[PATH_MAX]; 212 char path[PATH_MAX];
215 const char *sysfs;
216 FILE *file; 213 FILE *file;
217 int ret = 0; 214 int ret = 0;
215 const char *sysfs = sysfs__mountpoint();
218 216
219 sysfs = sysfs_find_mountpoint();
220 if (!sysfs) 217 if (!sysfs)
221 return -1; 218 return -1;
222 219
@@ -241,11 +238,10 @@ static int pmu_type(const char *name, __u32 *type)
241static void pmu_read_sysfs(void) 238static void pmu_read_sysfs(void)
242{ 239{
243 char path[PATH_MAX]; 240 char path[PATH_MAX];
244 const char *sysfs;
245 DIR *dir; 241 DIR *dir;
246 struct dirent *dent; 242 struct dirent *dent;
243 const char *sysfs = sysfs__mountpoint();
247 244
248 sysfs = sysfs_find_mountpoint();
249 if (!sysfs) 245 if (!sysfs)
250 return; 246 return;
251 247
@@ -270,11 +266,10 @@ static struct cpu_map *pmu_cpumask(const char *name)
270{ 266{
271 struct stat st; 267 struct stat st;
272 char path[PATH_MAX]; 268 char path[PATH_MAX];
273 const char *sysfs;
274 FILE *file; 269 FILE *file;
275 struct cpu_map *cpus; 270 struct cpu_map *cpus;
271 const char *sysfs = sysfs__mountpoint();
276 272
277 sysfs = sysfs_find_mountpoint();
278 if (!sysfs) 273 if (!sysfs)
279 return NULL; 274 return NULL;
280 275
@@ -637,3 +632,19 @@ void print_pmu_events(const char *event_glob, bool name_only)
637 printf("\n"); 632 printf("\n");
638 free(aliases); 633 free(aliases);
639} 634}
635
636bool pmu_have_event(const char *pname, const char *name)
637{
638 struct perf_pmu *pmu;
639 struct perf_pmu_alias *alias;
640
641 pmu = NULL;
642 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
643 if (strcmp(pname, pmu->name))
644 continue;
645 list_for_each_entry(alias, &pmu->aliases, list)
646 if (!strcmp(alias->name, name))
647 return true;
648 }
649 return false;
650}
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 6b2cbe2d4cc3..1179b26f244a 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -42,6 +42,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
42struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 42struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
43 43
44void print_pmu_events(const char *event_glob, bool name_only); 44void print_pmu_events(const char *event_glob, bool name_only);
45bool pmu_have_event(const char *pname, const char *name);
45 46
46int perf_pmu__test(void); 47int perf_pmu__test(void);
47#endif /* __PMU_H */ 48#endif /* __PMU_H */
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index aa04bf9c9ad7..9c6989ca2bea 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -47,7 +47,6 @@
47#include "session.h" 47#include "session.h"
48 48
49#define MAX_CMDLEN 256 49#define MAX_CMDLEN 256
50#define MAX_PROBE_ARGS 128
51#define PERFPROBE_GROUP "probe" 50#define PERFPROBE_GROUP "probe"
52 51
53bool probe_event_dry_run; /* Dry run flag */ 52bool probe_event_dry_run; /* Dry run flag */
@@ -201,7 +200,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp,
201 return 0; 200 return 0;
202} 201}
203 202
204#ifdef DWARF_SUPPORT 203#ifdef HAVE_DWARF_SUPPORT
205/* Open new debuginfo of given module */ 204/* Open new debuginfo of given module */
206static struct debuginfo *open_debuginfo(const char *module) 205static struct debuginfo *open_debuginfo(const char *module)
207{ 206{
@@ -630,7 +629,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
630 return ret; 629 return ret;
631} 630}
632 631
633#else /* !DWARF_SUPPORT */ 632#else /* !HAVE_DWARF_SUPPORT */
634 633
635static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 634static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
636 struct perf_probe_point *pp) 635 struct perf_probe_point *pp)
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c09e0a9fdf4c..ffb657ffd327 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -115,7 +115,7 @@ static const Dwfl_Callbacks offline_callbacks = {
115}; 115};
116 116
117/* Get a Dwarf from offline image */ 117/* Get a Dwarf from offline image */
118static int debuginfo__init_offline_dwarf(struct debuginfo *self, 118static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,
119 const char *path) 119 const char *path)
120{ 120{
121 int fd; 121 int fd;
@@ -124,25 +124,25 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *self,
124 if (fd < 0) 124 if (fd < 0)
125 return fd; 125 return fd;
126 126
127 self->dwfl = dwfl_begin(&offline_callbacks); 127 dbg->dwfl = dwfl_begin(&offline_callbacks);
128 if (!self->dwfl) 128 if (!dbg->dwfl)
129 goto error; 129 goto error;
130 130
131 self->mod = dwfl_report_offline(self->dwfl, "", "", fd); 131 dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);
132 if (!self->mod) 132 if (!dbg->mod)
133 goto error; 133 goto error;
134 134
135 self->dbg = dwfl_module_getdwarf(self->mod, &self->bias); 135 dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);
136 if (!self->dbg) 136 if (!dbg->dbg)
137 goto error; 137 goto error;
138 138
139 return 0; 139 return 0;
140error: 140error:
141 if (self->dwfl) 141 if (dbg->dwfl)
142 dwfl_end(self->dwfl); 142 dwfl_end(dbg->dwfl);
143 else 143 else
144 close(fd); 144 close(fd);
145 memset(self, 0, sizeof(*self)); 145 memset(dbg, 0, sizeof(*dbg));
146 146
147 return -ENOENT; 147 return -ENOENT;
148} 148}
@@ -180,24 +180,24 @@ static const Dwfl_Callbacks kernel_callbacks = {
180}; 180};
181 181
182/* Get a Dwarf from live kernel image */ 182/* Get a Dwarf from live kernel image */
183static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 183static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
184 Dwarf_Addr addr) 184 Dwarf_Addr addr)
185{ 185{
186 self->dwfl = dwfl_begin(&kernel_callbacks); 186 dbg->dwfl = dwfl_begin(&kernel_callbacks);
187 if (!self->dwfl) 187 if (!dbg->dwfl)
188 return -EINVAL; 188 return -EINVAL;
189 189
190 /* Load the kernel dwarves: Don't care the result here */ 190 /* Load the kernel dwarves: Don't care the result here */
191 dwfl_linux_kernel_report_kernel(self->dwfl); 191 dwfl_linux_kernel_report_kernel(dbg->dwfl);
192 dwfl_linux_kernel_report_modules(self->dwfl); 192 dwfl_linux_kernel_report_modules(dbg->dwfl);
193 193
194 self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); 194 dbg->dbg = dwfl_addrdwarf(dbg->dwfl, addr, &dbg->bias);
195 /* Here, check whether we could get a real dwarf */ 195 /* Here, check whether we could get a real dwarf */
196 if (!self->dbg) { 196 if (!dbg->dbg) {
197 pr_debug("Failed to find kernel dwarf at %lx\n", 197 pr_debug("Failed to find kernel dwarf at %lx\n",
198 (unsigned long)addr); 198 (unsigned long)addr);
199 dwfl_end(self->dwfl); 199 dwfl_end(dbg->dwfl);
200 memset(self, 0, sizeof(*self)); 200 memset(dbg, 0, sizeof(*dbg));
201 return -ENOENT; 201 return -ENOENT;
202 } 202 }
203 203
@@ -205,7 +205,7 @@ static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
205} 205}
206#else 206#else
207/* With older elfutils, this just support kernel module... */ 207/* With older elfutils, this just support kernel module... */
208static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, 208static int debuginfo__init_online_kernel_dwarf(struct debuginfo *dbg,
209 Dwarf_Addr addr __maybe_unused) 209 Dwarf_Addr addr __maybe_unused)
210{ 210{
211 const char *path = kernel_get_module_path("kernel"); 211 const char *path = kernel_get_module_path("kernel");
@@ -216,44 +216,45 @@ static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self,
216 } 216 }
217 217
218 pr_debug2("Use file %s for debuginfo\n", path); 218 pr_debug2("Use file %s for debuginfo\n", path);
219 return debuginfo__init_offline_dwarf(self, path); 219 return debuginfo__init_offline_dwarf(dbg, path);
220} 220}
221#endif 221#endif
222 222
223struct debuginfo *debuginfo__new(const char *path) 223struct debuginfo *debuginfo__new(const char *path)
224{ 224{
225 struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 225 struct debuginfo *dbg = zalloc(sizeof(*dbg));
226 if (!self) 226 if (!dbg)
227 return NULL; 227 return NULL;
228 228
229 if (debuginfo__init_offline_dwarf(self, path) < 0) { 229 if (debuginfo__init_offline_dwarf(dbg, path) < 0) {
230 free(self); 230 free(dbg);
231 self = NULL; 231 dbg = NULL;
232 } 232 }
233 233
234 return self; 234 return dbg;
235} 235}
236 236
237struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) 237struct debuginfo *debuginfo__new_online_kernel(unsigned long addr)
238{ 238{
239 struct debuginfo *self = zalloc(sizeof(struct debuginfo)); 239 struct debuginfo *dbg = zalloc(sizeof(*dbg));
240 if (!self) 240
241 if (!dbg)
241 return NULL; 242 return NULL;
242 243
243 if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { 244 if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) {
244 free(self); 245 free(dbg);
245 self = NULL; 246 dbg = NULL;
246 } 247 }
247 248
248 return self; 249 return dbg;
249} 250}
250 251
251void debuginfo__delete(struct debuginfo *self) 252void debuginfo__delete(struct debuginfo *dbg)
252{ 253{
253 if (self) { 254 if (dbg) {
254 if (self->dwfl) 255 if (dbg->dwfl)
255 dwfl_end(self->dwfl); 256 dwfl_end(dbg->dwfl);
256 free(self); 257 free(dbg);
257 } 258 }
258} 259}
259 260
@@ -273,12 +274,15 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
273/* 274/*
274 * Convert a location into trace_arg. 275 * Convert a location into trace_arg.
275 * If tvar == NULL, this just checks variable can be converted. 276 * If tvar == NULL, this just checks variable can be converted.
277 * If fentry == true and vr_die is a parameter, do huristic search
278 * for the location fuzzed by function entry mcount.
276 */ 279 */
277static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 280static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
278 Dwarf_Op *fb_ops, 281 Dwarf_Op *fb_ops, Dwarf_Die *sp_die,
279 struct probe_trace_arg *tvar) 282 struct probe_trace_arg *tvar)
280{ 283{
281 Dwarf_Attribute attr; 284 Dwarf_Attribute attr;
285 Dwarf_Addr tmp = 0;
282 Dwarf_Op *op; 286 Dwarf_Op *op;
283 size_t nops; 287 size_t nops;
284 unsigned int regn; 288 unsigned int regn;
@@ -291,12 +295,29 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
291 goto static_var; 295 goto static_var;
292 296
293 /* TODO: handle more than 1 exprs */ 297 /* TODO: handle more than 1 exprs */
294 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 298 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
295 dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || 299 return -EINVAL; /* Broken DIE ? */
296 nops == 0) { 300 if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) {
297 /* TODO: Support const_value */ 301 ret = dwarf_entrypc(sp_die, &tmp);
302 if (ret || addr != tmp ||
303 dwarf_tag(vr_die) != DW_TAG_formal_parameter ||
304 dwarf_highpc(sp_die, &tmp))
305 return -ENOENT;
306 /*
307 * This is fuzzed by fentry mcount. We try to find the
308 * parameter location at the earliest address.
309 */
310 for (addr += 1; addr <= tmp; addr++) {
311 if (dwarf_getlocation_addr(&attr, addr, &op,
312 &nops, 1) > 0)
313 goto found;
314 }
298 return -ENOENT; 315 return -ENOENT;
299 } 316 }
317found:
318 if (nops == 0)
319 /* TODO: Support const_value */
320 return -ENOENT;
300 321
301 if (op->atom == DW_OP_addr) { 322 if (op->atom == DW_OP_addr) {
302static_var: 323static_var:
@@ -563,7 +584,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
563 } 584 }
564 585
565 if (die_find_member(&type, field->name, die_mem) == NULL) { 586 if (die_find_member(&type, field->name, die_mem) == NULL) {
566 pr_warning("%s(tyep:%s) has no member %s.\n", varname, 587 pr_warning("%s(type:%s) has no member %s.\n", varname,
567 dwarf_diename(&type), field->name); 588 dwarf_diename(&type), field->name);
568 return -EINVAL; 589 return -EINVAL;
569 } 590 }
@@ -600,7 +621,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
600 dwarf_diename(vr_die)); 621 dwarf_diename(vr_die));
601 622
602 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 623 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
603 pf->tvar); 624 &pf->sp_die, pf->tvar);
604 if (ret == -ENOENT) 625 if (ret == -ENOENT)
605 pr_err("Failed to find the location of %s at this address.\n" 626 pr_err("Failed to find the location of %s at this address.\n"
606 " Perhaps, it has been optimized out.\n", pf->pvar->var); 627 " Perhaps, it has been optimized out.\n", pf->pvar->var);
@@ -1063,7 +1084,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
1063} 1084}
1064 1085
1065/* Find probe points from debuginfo */ 1086/* Find probe points from debuginfo */
1066static int debuginfo__find_probes(struct debuginfo *self, 1087static int debuginfo__find_probes(struct debuginfo *dbg,
1067 struct probe_finder *pf) 1088 struct probe_finder *pf)
1068{ 1089{
1069 struct perf_probe_point *pp = &pf->pev->point; 1090 struct perf_probe_point *pp = &pf->pev->point;
@@ -1074,7 +1095,7 @@ static int debuginfo__find_probes(struct debuginfo *self,
1074 1095
1075#if _ELFUTILS_PREREQ(0, 142) 1096#if _ELFUTILS_PREREQ(0, 142)
1076 /* Get the call frame information from this dwarf */ 1097 /* Get the call frame information from this dwarf */
1077 pf->cfi = dwarf_getcfi(self->dbg); 1098 pf->cfi = dwarf_getcfi(dbg->dbg);
1078#endif 1099#endif
1079 1100
1080 off = 0; 1101 off = 0;
@@ -1093,7 +1114,7 @@ static int debuginfo__find_probes(struct debuginfo *self,
1093 .data = pf, 1114 .data = pf,
1094 }; 1115 };
1095 1116
1096 dwarf_getpubnames(self->dbg, pubname_search_cb, 1117 dwarf_getpubnames(dbg->dbg, pubname_search_cb,
1097 &pubname_param, 0); 1118 &pubname_param, 0);
1098 if (pubname_param.found) { 1119 if (pubname_param.found) {
1099 ret = probe_point_search_cb(&pf->sp_die, &probe_param); 1120 ret = probe_point_search_cb(&pf->sp_die, &probe_param);
@@ -1103,9 +1124,9 @@ static int debuginfo__find_probes(struct debuginfo *self,
1103 } 1124 }
1104 1125
1105 /* Loop on CUs (Compilation Unit) */ 1126 /* Loop on CUs (Compilation Unit) */
1106 while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 1127 while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
1107 /* Get the DIE(Debugging Information Entry) of this CU */ 1128 /* Get the DIE(Debugging Information Entry) of this CU */
1108 diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); 1129 diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die);
1109 if (!diep) 1130 if (!diep)
1110 continue; 1131 continue;
1111 1132
@@ -1136,12 +1157,80 @@ found:
1136 return ret; 1157 return ret;
1137} 1158}
1138 1159
1160struct local_vars_finder {
1161 struct probe_finder *pf;
1162 struct perf_probe_arg *args;
1163 int max_args;
1164 int nargs;
1165 int ret;
1166};
1167
1168/* Collect available variables in this scope */
1169static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
1170{
1171 struct local_vars_finder *vf = data;
1172 struct probe_finder *pf = vf->pf;
1173 int tag;
1174
1175 tag = dwarf_tag(die_mem);
1176 if (tag == DW_TAG_formal_parameter ||
1177 tag == DW_TAG_variable) {
1178 if (convert_variable_location(die_mem, vf->pf->addr,
1179 vf->pf->fb_ops, &pf->sp_die,
1180 NULL) == 0) {
1181 vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
1182 if (vf->args[vf->nargs].var == NULL) {
1183 vf->ret = -ENOMEM;
1184 return DIE_FIND_CB_END;
1185 }
1186 pr_debug(" %s", vf->args[vf->nargs].var);
1187 vf->nargs++;
1188 }
1189 }
1190
1191 if (dwarf_haspc(die_mem, vf->pf->addr))
1192 return DIE_FIND_CB_CONTINUE;
1193 else
1194 return DIE_FIND_CB_SIBLING;
1195}
1196
1197static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf,
1198 struct perf_probe_arg *args)
1199{
1200 Dwarf_Die die_mem;
1201 int i;
1202 int n = 0;
1203 struct local_vars_finder vf = {.pf = pf, .args = args,
1204 .max_args = MAX_PROBE_ARGS, .ret = 0};
1205
1206 for (i = 0; i < pf->pev->nargs; i++) {
1207 /* var never be NULL */
1208 if (strcmp(pf->pev->args[i].var, "$vars") == 0) {
1209 pr_debug("Expanding $vars into:");
1210 vf.nargs = n;
1211 /* Special local variables */
1212 die_find_child(sc_die, copy_variables_cb, (void *)&vf,
1213 &die_mem);
1214 pr_debug(" (%d)\n", vf.nargs - n);
1215 if (vf.ret < 0)
1216 return vf.ret;
1217 n = vf.nargs;
1218 } else {
1219 /* Copy normal argument */
1220 args[n] = pf->pev->args[i];
1221 n++;
1222 }
1223 }
1224 return n;
1225}
1226
1139/* Add a found probe point into trace event list */ 1227/* Add a found probe point into trace event list */
1140static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) 1228static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1141{ 1229{
1142 struct trace_event_finder *tf = 1230 struct trace_event_finder *tf =
1143 container_of(pf, struct trace_event_finder, pf); 1231 container_of(pf, struct trace_event_finder, pf);
1144 struct probe_trace_event *tev; 1232 struct probe_trace_event *tev;
1233 struct perf_probe_arg *args;
1145 int ret, i; 1234 int ret, i;
1146 1235
1147 /* Check number of tevs */ 1236 /* Check number of tevs */
@@ -1161,31 +1250,45 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1161 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1250 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1162 tev->point.offset); 1251 tev->point.offset);
1163 1252
1164 /* Find each argument */ 1253 /* Expand special probe argument if exist */
1165 tev->nargs = pf->pev->nargs; 1254 args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
1166 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1255 if (args == NULL)
1167 if (tev->args == NULL)
1168 return -ENOMEM; 1256 return -ENOMEM;
1169 for (i = 0; i < pf->pev->nargs; i++) { 1257
1170 pf->pvar = &pf->pev->args[i]; 1258 ret = expand_probe_args(sc_die, pf, args);
1259 if (ret < 0)
1260 goto end;
1261
1262 tev->nargs = ret;
1263 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1264 if (tev->args == NULL) {
1265 ret = -ENOMEM;
1266 goto end;
1267 }
1268
1269 /* Find each argument */
1270 for (i = 0; i < tev->nargs; i++) {
1271 pf->pvar = &args[i];
1171 pf->tvar = &tev->args[i]; 1272 pf->tvar = &tev->args[i];
1172 /* Variable should be found from scope DIE */ 1273 /* Variable should be found from scope DIE */
1173 ret = find_variable(sc_die, pf); 1274 ret = find_variable(sc_die, pf);
1174 if (ret != 0) 1275 if (ret != 0)
1175 return ret; 1276 break;
1176 } 1277 }
1177 1278
1178 return 0; 1279end:
1280 free(args);
1281 return ret;
1179} 1282}
1180 1283
1181/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1284/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1182int debuginfo__find_trace_events(struct debuginfo *self, 1285int debuginfo__find_trace_events(struct debuginfo *dbg,
1183 struct perf_probe_event *pev, 1286 struct perf_probe_event *pev,
1184 struct probe_trace_event **tevs, int max_tevs) 1287 struct probe_trace_event **tevs, int max_tevs)
1185{ 1288{
1186 struct trace_event_finder tf = { 1289 struct trace_event_finder tf = {
1187 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1290 .pf = {.pev = pev, .callback = add_probe_trace_event},
1188 .mod = self->mod, .max_tevs = max_tevs}; 1291 .mod = dbg->mod, .max_tevs = max_tevs};
1189 int ret; 1292 int ret;
1190 1293
1191 /* Allocate result tevs array */ 1294 /* Allocate result tevs array */
@@ -1196,7 +1299,7 @@ int debuginfo__find_trace_events(struct debuginfo *self,
1196 tf.tevs = *tevs; 1299 tf.tevs = *tevs;
1197 tf.ntevs = 0; 1300 tf.ntevs = 0;
1198 1301
1199 ret = debuginfo__find_probes(self, &tf.pf); 1302 ret = debuginfo__find_probes(dbg, &tf.pf);
1200 if (ret < 0) { 1303 if (ret < 0) {
1201 free(*tevs); 1304 free(*tevs);
1202 *tevs = NULL; 1305 *tevs = NULL;
@@ -1222,7 +1325,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1222 if (tag == DW_TAG_formal_parameter || 1325 if (tag == DW_TAG_formal_parameter ||
1223 tag == DW_TAG_variable) { 1326 tag == DW_TAG_variable) {
1224 ret = convert_variable_location(die_mem, af->pf.addr, 1327 ret = convert_variable_location(die_mem, af->pf.addr,
1225 af->pf.fb_ops, NULL); 1328 af->pf.fb_ops, &af->pf.sp_die,
1329 NULL);
1226 if (ret == 0) { 1330 if (ret == 0) {
1227 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); 1331 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1228 pr_debug2("Add new var: %s\n", buf); 1332 pr_debug2("Add new var: %s\n", buf);
@@ -1286,14 +1390,14 @@ out:
1286} 1390}
1287 1391
1288/* Find available variables at given probe point */ 1392/* Find available variables at given probe point */
1289int debuginfo__find_available_vars_at(struct debuginfo *self, 1393int debuginfo__find_available_vars_at(struct debuginfo *dbg,
1290 struct perf_probe_event *pev, 1394 struct perf_probe_event *pev,
1291 struct variable_list **vls, 1395 struct variable_list **vls,
1292 int max_vls, bool externs) 1396 int max_vls, bool externs)
1293{ 1397{
1294 struct available_var_finder af = { 1398 struct available_var_finder af = {
1295 .pf = {.pev = pev, .callback = add_available_vars}, 1399 .pf = {.pev = pev, .callback = add_available_vars},
1296 .mod = self->mod, 1400 .mod = dbg->mod,
1297 .max_vls = max_vls, .externs = externs}; 1401 .max_vls = max_vls, .externs = externs};
1298 int ret; 1402 int ret;
1299 1403
@@ -1305,7 +1409,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self,
1305 af.vls = *vls; 1409 af.vls = *vls;
1306 af.nvls = 0; 1410 af.nvls = 0;
1307 1411
1308 ret = debuginfo__find_probes(self, &af.pf); 1412 ret = debuginfo__find_probes(dbg, &af.pf);
1309 if (ret < 0) { 1413 if (ret < 0) {
1310 /* Free vlist for error */ 1414 /* Free vlist for error */
1311 while (af.nvls--) { 1415 while (af.nvls--) {
@@ -1323,7 +1427,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *self,
1323} 1427}
1324 1428
1325/* Reverse search */ 1429/* Reverse search */
1326int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, 1430int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
1327 struct perf_probe_point *ppt) 1431 struct perf_probe_point *ppt)
1328{ 1432{
1329 Dwarf_Die cudie, spdie, indie; 1433 Dwarf_Die cudie, spdie, indie;
@@ -1332,10 +1436,10 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1332 int baseline = 0, lineno = 0, ret = 0; 1436 int baseline = 0, lineno = 0, ret = 0;
1333 1437
1334 /* Adjust address with bias */ 1438 /* Adjust address with bias */
1335 addr += self->bias; 1439 addr += dbg->bias;
1336 1440
1337 /* Find cu die */ 1441 /* Find cu die */
1338 if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { 1442 if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr - dbg->bias, &cudie)) {
1339 pr_warning("Failed to find debug information for address %lx\n", 1443 pr_warning("Failed to find debug information for address %lx\n",
1340 addr); 1444 addr);
1341 ret = -EINVAL; 1445 ret = -EINVAL;
@@ -1357,10 +1461,10 @@ int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr,
1357 goto post; 1461 goto post;
1358 } 1462 }
1359 1463
1464 fname = dwarf_decl_file(&spdie);
1360 if (addr == (unsigned long)baseaddr) { 1465 if (addr == (unsigned long)baseaddr) {
1361 /* Function entry - Relative line number is 0 */ 1466 /* Function entry - Relative line number is 0 */
1362 lineno = baseline; 1467 lineno = baseline;
1363 fname = dwarf_decl_file(&spdie);
1364 goto post; 1468 goto post;
1365 } 1469 }
1366 1470
@@ -1536,7 +1640,7 @@ static int find_line_range_by_func(struct line_finder *lf)
1536 return param.retval; 1640 return param.retval;
1537} 1641}
1538 1642
1539int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) 1643int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr)
1540{ 1644{
1541 struct line_finder lf = {.lr = lr, .found = 0}; 1645 struct line_finder lf = {.lr = lr, .found = 0};
1542 int ret = 0; 1646 int ret = 0;
@@ -1553,7 +1657,7 @@ int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr)
1553 struct dwarf_callback_param line_range_param = { 1657 struct dwarf_callback_param line_range_param = {
1554 .data = (void *)&lf, .retval = 0}; 1658 .data = (void *)&lf, .retval = 0};
1555 1659
1556 dwarf_getpubnames(self->dbg, pubname_search_cb, 1660 dwarf_getpubnames(dbg->dbg, pubname_search_cb,
1557 &pubname_param, 0); 1661 &pubname_param, 0);
1558 if (pubname_param.found) { 1662 if (pubname_param.found) {
1559 line_range_search_cb(&lf.sp_die, &line_range_param); 1663 line_range_search_cb(&lf.sp_die, &line_range_param);
@@ -1564,12 +1668,12 @@ int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr)
1564 1668
1565 /* Loop on CUs (Compilation Unit) */ 1669 /* Loop on CUs (Compilation Unit) */
1566 while (!lf.found && ret >= 0) { 1670 while (!lf.found && ret >= 0) {
1567 if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, 1671 if (dwarf_nextcu(dbg->dbg, off, &noff, &cuhl,
1568 NULL, NULL, NULL) != 0) 1672 NULL, NULL, NULL) != 0)
1569 break; 1673 break;
1570 1674
1571 /* Get the DIE(Debugging Information Entry) of this CU */ 1675 /* Get the DIE(Debugging Information Entry) of this CU */
1572 diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); 1676 diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die);
1573 if (!diep) 1677 if (!diep)
1574 continue; 1678 continue;
1575 1679
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 3b7d63018960..ffc33cdd25cc 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -7,6 +7,7 @@
7 7
8#define MAX_PROBE_BUFFER 1024 8#define MAX_PROBE_BUFFER 1024
9#define MAX_PROBES 128 9#define MAX_PROBES 128
10#define MAX_PROBE_ARGS 128
10 11
11static inline int is_c_varname(const char *name) 12static inline int is_c_varname(const char *name)
12{ 13{
@@ -14,7 +15,7 @@ static inline int is_c_varname(const char *name)
14 return isalpha(name[0]) || name[0] == '_'; 15 return isalpha(name[0]) || name[0] == '_';
15} 16}
16 17
17#ifdef DWARF_SUPPORT 18#ifdef HAVE_DWARF_SUPPORT
18 19
19#include "dwarf-aux.h" 20#include "dwarf-aux.h"
20 21
@@ -30,25 +31,25 @@ struct debuginfo {
30 31
31extern struct debuginfo *debuginfo__new(const char *path); 32extern struct debuginfo *debuginfo__new(const char *path);
32extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr); 33extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr);
33extern void debuginfo__delete(struct debuginfo *self); 34extern void debuginfo__delete(struct debuginfo *dbg);
34 35
35/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 36/* Find probe_trace_events specified by perf_probe_event from debuginfo */
36extern int debuginfo__find_trace_events(struct debuginfo *self, 37extern int debuginfo__find_trace_events(struct debuginfo *dbg,
37 struct perf_probe_event *pev, 38 struct perf_probe_event *pev,
38 struct probe_trace_event **tevs, 39 struct probe_trace_event **tevs,
39 int max_tevs); 40 int max_tevs);
40 41
41/* Find a perf_probe_point from debuginfo */ 42/* Find a perf_probe_point from debuginfo */
42extern int debuginfo__find_probe_point(struct debuginfo *self, 43extern int debuginfo__find_probe_point(struct debuginfo *dbg,
43 unsigned long addr, 44 unsigned long addr,
44 struct perf_probe_point *ppt); 45 struct perf_probe_point *ppt);
45 46
46/* Find a line range */ 47/* Find a line range */
47extern int debuginfo__find_line_range(struct debuginfo *self, 48extern int debuginfo__find_line_range(struct debuginfo *dbg,
48 struct line_range *lr); 49 struct line_range *lr);
49 50
50/* Find available variables */ 51/* Find available variables */
51extern int debuginfo__find_available_vars_at(struct debuginfo *self, 52extern int debuginfo__find_available_vars_at(struct debuginfo *dbg,
52 struct perf_probe_event *pev, 53 struct perf_probe_event *pev,
53 struct variable_list **vls, 54 struct variable_list **vls,
54 int max_points, bool externs); 55 int max_points, bool externs);
@@ -105,6 +106,6 @@ struct line_finder {
105 int found; 106 int found;
106}; 107};
107 108
108#endif /* DWARF_SUPPORT */ 109#endif /* HAVE_DWARF_SUPPORT */
109 110
110#endif /*_PROBE_FINDER_H */ 111#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/pstack.h b/tools/perf/util/pstack.h
index 4cedea59f518..c3cb6584d527 100644
--- a/tools/perf/util/pstack.h
+++ b/tools/perf/util/pstack.h
@@ -5,10 +5,10 @@
5 5
6struct pstack; 6struct pstack;
7struct pstack *pstack__new(unsigned short max_nr_entries); 7struct pstack *pstack__new(unsigned short max_nr_entries);
8void pstack__delete(struct pstack *self); 8void pstack__delete(struct pstack *pstack);
9bool pstack__empty(const struct pstack *self); 9bool pstack__empty(const struct pstack *pstack);
10void pstack__remove(struct pstack *self, void *key); 10void pstack__remove(struct pstack *pstack, void *key);
11void pstack__push(struct pstack *self, void *key); 11void pstack__push(struct pstack *pstack, void *key);
12void *pstack__pop(struct pstack *self); 12void *pstack__pop(struct pstack *pstack);
13 13
14#endif /* _PERF_PSTACK_ */ 14#endif /* _PERF_PSTACK_ */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index f75ae1b9900c..239036fb2b2c 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -17,5 +17,5 @@ util/xyarray.c
17util/cgroup.c 17util/cgroup.c
18util/rblist.c 18util/rblist.c
19util/strlist.c 19util/strlist.c
20util/sysfs.c 20util/fs.c
21../../lib/rbtree.c 21../../lib/rbtree.c
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 71b5412bbbb9..4bf8ace7f511 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -33,13 +33,6 @@ int eprintf(int level, const char *fmt, ...)
33# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, 33# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
34#endif 34#endif
35 35
36struct throttle_event {
37 struct perf_event_header header;
38 u64 time;
39 u64 id;
40 u64 stream_id;
41};
42
43PyMODINIT_FUNC initperf(void); 36PyMODINIT_FUNC initperf(void);
44 37
45#define member_def(type, member, ptype, help) \ 38#define member_def(type, member, ptype, help) \
@@ -822,6 +815,8 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
822 PyObject *pyevent = pyrf_event__new(event); 815 PyObject *pyevent = pyrf_event__new(event);
823 struct pyrf_event *pevent = (struct pyrf_event *)pyevent; 816 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
824 817
818 perf_evlist__mmap_consume(evlist, cpu);
819
825 if (pyevent == NULL) 820 if (pyevent == NULL)
826 return PyErr_NoMemory(); 821 return PyErr_NoMemory();
827 822
@@ -1036,6 +1031,7 @@ PyMODINIT_FUNC initperf(void)
1036 pyrf_cpu_map__setup_types() < 0) 1031 pyrf_cpu_map__setup_types() < 0)
1037 return; 1032 return;
1038 1033
1034 /* The page_size is placed in util object. */
1039 page_size = sysconf(_SC_PAGE_SIZE); 1035 page_size = sysconf(_SC_PAGE_SIZE);
1040 1036
1041 Py_INCREF(&pyrf_evlist__type); 1037 Py_INCREF(&pyrf_evlist__type);
diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c
index a16cdd2625ad..0dfe27d99458 100644
--- a/tools/perf/util/rblist.c
+++ b/tools/perf/util/rblist.c
@@ -48,10 +48,12 @@ void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
48 rblist->node_delete(rblist, rb_node); 48 rblist->node_delete(rblist, rb_node);
49} 49}
50 50
51struct rb_node *rblist__find(struct rblist *rblist, const void *entry) 51static struct rb_node *__rblist__findnew(struct rblist *rblist,
52 const void *entry,
53 bool create)
52{ 54{
53 struct rb_node **p = &rblist->entries.rb_node; 55 struct rb_node **p = &rblist->entries.rb_node;
54 struct rb_node *parent = NULL; 56 struct rb_node *parent = NULL, *new_node = NULL;
55 57
56 while (*p != NULL) { 58 while (*p != NULL) {
57 int rc; 59 int rc;
@@ -67,7 +69,26 @@ struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
67 return parent; 69 return parent;
68 } 70 }
69 71
70 return NULL; 72 if (create) {
73 new_node = rblist->node_new(rblist, entry);
74 if (new_node) {
75 rb_link_node(new_node, parent, p);
76 rb_insert_color(new_node, &rblist->entries);
77 ++rblist->nr_entries;
78 }
79 }
80
81 return new_node;
82}
83
84struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
85{
86 return __rblist__findnew(rblist, entry, false);
87}
88
89struct rb_node *rblist__findnew(struct rblist *rblist, const void *entry)
90{
91 return __rblist__findnew(rblist, entry, true);
71} 92}
72 93
73void rblist__init(struct rblist *rblist) 94void rblist__init(struct rblist *rblist)
diff --git a/tools/perf/util/rblist.h b/tools/perf/util/rblist.h
index 6d0cae5ae83d..ff9913b994c2 100644
--- a/tools/perf/util/rblist.h
+++ b/tools/perf/util/rblist.h
@@ -32,6 +32,7 @@ void rblist__delete(struct rblist *rblist);
32int rblist__add_node(struct rblist *rblist, const void *new_entry); 32int rblist__add_node(struct rblist *rblist, const void *new_entry);
33void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node); 33void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node);
34struct rb_node *rblist__find(struct rblist *rblist, const void *entry); 34struct rb_node *rblist__find(struct rblist *rblist, const void *entry);
35struct rb_node *rblist__findnew(struct rblist *rblist, const void *entry);
35struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx); 36struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx);
36 37
37static inline bool rblist__empty(const struct rblist *rblist) 38static inline bool rblist__empty(const struct rblist *rblist)
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 18d73aa2f0f8..c8845b107f60 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -2,6 +2,8 @@
2#include "evsel.h" 2#include "evsel.h"
3#include "cpumap.h" 3#include "cpumap.h"
4#include "parse-events.h" 4#include "parse-events.h"
5#include "fs.h"
6#include "util.h"
5 7
6typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 8typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
7 9
@@ -106,3 +108,72 @@ void perf_evlist__config(struct perf_evlist *evlist,
106 108
107 perf_evlist__set_id_pos(evlist); 109 perf_evlist__set_id_pos(evlist);
108} 110}
111
112static int get_max_rate(unsigned int *rate)
113{
114 char path[PATH_MAX];
115 const char *procfs = procfs__mountpoint();
116
117 if (!procfs)
118 return -1;
119
120 snprintf(path, PATH_MAX,
121 "%s/sys/kernel/perf_event_max_sample_rate", procfs);
122
123 return filename__read_int(path, (int *) rate);
124}
125
126static int perf_record_opts__config_freq(struct perf_record_opts *opts)
127{
128 bool user_freq = opts->user_freq != UINT_MAX;
129 unsigned int max_rate;
130
131 if (opts->user_interval != ULLONG_MAX)
132 opts->default_interval = opts->user_interval;
133 if (user_freq)
134 opts->freq = opts->user_freq;
135
136 /*
137 * User specified count overrides default frequency.
138 */
139 if (opts->default_interval)
140 opts->freq = 0;
141 else if (opts->freq) {
142 opts->default_interval = opts->freq;
143 } else {
144 pr_err("frequency and count are zero, aborting\n");
145 return -1;
146 }
147
148 if (get_max_rate(&max_rate))
149 return 0;
150
151 /*
152 * User specified frequency is over current maximum.
153 */
154 if (user_freq && (max_rate < opts->freq)) {
155 pr_err("Maximum frequency rate (%u) reached.\n"
156 "Please use -F freq option with lower value or consider\n"
157 "tweaking /proc/sys/kernel/perf_event_max_sample_rate.\n",
158 max_rate);
159 return -1;
160 }
161
162 /*
163 * Default frequency is over current maximum.
164 */
165 if (max_rate < opts->freq) {
166 pr_warning("Lowering default frequency rate to %u.\n"
167 "Please consider tweaking "
168 "/proc/sys/kernel/perf_event_max_sample_rate.\n",
169 max_rate);
170 opts->freq = max_rate;
171 }
172
173 return 0;
174}
175
176int perf_record_opts__config(struct perf_record_opts *opts)
177{
178 return perf_record_opts__config_freq(opts);
179}
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index a85e4ae5f3ac..d5e5969f6fea 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -273,7 +273,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
273 int cpu = sample->cpu; 273 int cpu = sample->cpu;
274 void *data = sample->raw_data; 274 void *data = sample->raw_data;
275 unsigned long long nsecs = sample->time; 275 unsigned long long nsecs = sample->time;
276 char *comm = thread->comm; 276 const char *comm = thread__comm_str(thread);
277 277
278 dSP; 278 dSP;
279 279
@@ -282,7 +282,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused,
282 282
283 event = find_cache_event(evsel); 283 event = find_cache_event(evsel);
284 if (!event) 284 if (!event)
285 die("ug! no event found for type %" PRIu64, evsel->attr.config); 285 die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config);
286 286
287 pid = raw_field_value(event, "common_pid", data); 287 pid = raw_field_value(event, "common_pid", data);
288 288
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index cc75a3cef388..53c20e7fd900 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -56,6 +56,17 @@ static void handler_call_die(const char *handler_name)
56 Py_FatalError("problem in Python trace event handler"); 56 Py_FatalError("problem in Python trace event handler");
57} 57}
58 58
59/*
60 * Insert val into into the dictionary and decrement the reference counter.
61 * This is necessary for dictionaries since PyDict_SetItemString() does not
62 * steal a reference, as opposed to PyTuple_SetItem().
63 */
64static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObject *val)
65{
66 PyDict_SetItemString(dict, key, val);
67 Py_DECREF(val);
68}
69
59static void define_value(enum print_arg_type field_type, 70static void define_value(enum print_arg_type field_type,
60 const char *ev_name, 71 const char *ev_name,
61 const char *field_name, 72 const char *field_name,
@@ -239,7 +250,7 @@ static void python_process_tracepoint(union perf_event *perf_event
239 int cpu = sample->cpu; 250 int cpu = sample->cpu;
240 void *data = sample->raw_data; 251 void *data = sample->raw_data;
241 unsigned long long nsecs = sample->time; 252 unsigned long long nsecs = sample->time;
242 char *comm = thread->comm; 253 const char *comm = thread__comm_str(thread);
243 254
244 t = PyTuple_New(MAX_FIELDS); 255 t = PyTuple_New(MAX_FIELDS);
245 if (!t) 256 if (!t)
@@ -279,11 +290,11 @@ static void python_process_tracepoint(union perf_event *perf_event
279 PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); 290 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
280 PyTuple_SetItem(t, n++, PyString_FromString(comm)); 291 PyTuple_SetItem(t, n++, PyString_FromString(comm));
281 } else { 292 } else {
282 PyDict_SetItemString(dict, "common_cpu", PyInt_FromLong(cpu)); 293 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu));
283 PyDict_SetItemString(dict, "common_s", PyInt_FromLong(s)); 294 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s));
284 PyDict_SetItemString(dict, "common_ns", PyInt_FromLong(ns)); 295 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns));
285 PyDict_SetItemString(dict, "common_pid", PyInt_FromLong(pid)); 296 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid));
286 PyDict_SetItemString(dict, "common_comm", PyString_FromString(comm)); 297 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm));
287 } 298 }
288 for (field = event->format.fields; field; field = field->next) { 299 for (field = event->format.fields; field; field = field->next) {
289 if (field->flags & FIELD_IS_STRING) { 300 if (field->flags & FIELD_IS_STRING) {
@@ -313,7 +324,7 @@ static void python_process_tracepoint(union perf_event *perf_event
313 if (handler) 324 if (handler)
314 PyTuple_SetItem(t, n++, obj); 325 PyTuple_SetItem(t, n++, obj);
315 else 326 else
316 PyDict_SetItemString(dict, field->name, obj); 327 pydict_set_item_string_decref(dict, field->name, obj);
317 328
318 } 329 }
319 if (!handler) 330 if (!handler)
@@ -370,21 +381,21 @@ static void python_process_general_event(union perf_event *perf_event
370 if (!handler || !PyCallable_Check(handler)) 381 if (!handler || !PyCallable_Check(handler))
371 goto exit; 382 goto exit;
372 383
373 PyDict_SetItemString(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); 384 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
374 PyDict_SetItemString(dict, "attr", PyString_FromStringAndSize( 385 pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize(
375 (const char *)&evsel->attr, sizeof(evsel->attr))); 386 (const char *)&evsel->attr, sizeof(evsel->attr)));
376 PyDict_SetItemString(dict, "sample", PyString_FromStringAndSize( 387 pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize(
377 (const char *)sample, sizeof(*sample))); 388 (const char *)sample, sizeof(*sample)));
378 PyDict_SetItemString(dict, "raw_buf", PyString_FromStringAndSize( 389 pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize(
379 (const char *)sample->raw_data, sample->raw_size)); 390 (const char *)sample->raw_data, sample->raw_size));
380 PyDict_SetItemString(dict, "comm", 391 pydict_set_item_string_decref(dict, "comm",
381 PyString_FromString(thread->comm)); 392 PyString_FromString(thread__comm_str(thread)));
382 if (al->map) { 393 if (al->map) {
383 PyDict_SetItemString(dict, "dso", 394 pydict_set_item_string_decref(dict, "dso",
384 PyString_FromString(al->map->dso->name)); 395 PyString_FromString(al->map->dso->name));
385 } 396 }
386 if (al->sym) { 397 if (al->sym) {
387 PyDict_SetItemString(dict, "symbol", 398 pydict_set_item_string_decref(dict, "symbol",
388 PyString_FromString(al->sym->name)); 399 PyString_FromString(al->sym->name));
389 } 400 }
390 401
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 568b750c01f6..f36d24a02445 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -16,73 +16,34 @@
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "vdso.h" 17#include "vdso.h"
18 18
19static int perf_session__open(struct perf_session *self, bool force) 19static int perf_session__open(struct perf_session *session)
20{ 20{
21 struct stat input_stat; 21 struct perf_data_file *file = session->file;
22 22
23 if (!strcmp(self->filename, "-")) { 23 if (perf_session__read_header(session) < 0) {
24 self->fd_pipe = true;
25 self->fd = STDIN_FILENO;
26
27 if (perf_session__read_header(self) < 0)
28 pr_err("incompatible file format (rerun with -v to learn more)");
29
30 return 0;
31 }
32
33 self->fd = open(self->filename, O_RDONLY);
34 if (self->fd < 0) {
35 int err = errno;
36
37 pr_err("failed to open %s: %s", self->filename, strerror(err));
38 if (err == ENOENT && !strcmp(self->filename, "perf.data"))
39 pr_err(" (try 'perf record' first)");
40 pr_err("\n");
41 return -errno;
42 }
43
44 if (fstat(self->fd, &input_stat) < 0)
45 goto out_close;
46
47 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
48 pr_err("file %s not owned by current user or root\n",
49 self->filename);
50 goto out_close;
51 }
52
53 if (!input_stat.st_size) {
54 pr_info("zero-sized file (%s), nothing to do!\n",
55 self->filename);
56 goto out_close;
57 }
58
59 if (perf_session__read_header(self) < 0) {
60 pr_err("incompatible file format (rerun with -v to learn more)"); 24 pr_err("incompatible file format (rerun with -v to learn more)");
61 goto out_close; 25 return -1;
62 } 26 }
63 27
64 if (!perf_evlist__valid_sample_type(self->evlist)) { 28 if (perf_data_file__is_pipe(file))
29 return 0;
30
31 if (!perf_evlist__valid_sample_type(session->evlist)) {
65 pr_err("non matching sample_type"); 32 pr_err("non matching sample_type");
66 goto out_close; 33 return -1;
67 } 34 }
68 35
69 if (!perf_evlist__valid_sample_id_all(self->evlist)) { 36 if (!perf_evlist__valid_sample_id_all(session->evlist)) {
70 pr_err("non matching sample_id_all"); 37 pr_err("non matching sample_id_all");
71 goto out_close; 38 return -1;
72 } 39 }
73 40
74 if (!perf_evlist__valid_read_format(self->evlist)) { 41 if (!perf_evlist__valid_read_format(session->evlist)) {
75 pr_err("non matching read_format"); 42 pr_err("non matching read_format");
76 goto out_close; 43 return -1;
77 } 44 }
78 45
79 self->size = input_stat.st_size;
80 return 0; 46 return 0;
81
82out_close:
83 close(self->fd);
84 self->fd = -1;
85 return -1;
86} 47}
87 48
88void perf_session__set_id_hdr_size(struct perf_session *session) 49void perf_session__set_id_hdr_size(struct perf_session *session)
@@ -92,71 +53,70 @@ void perf_session__set_id_hdr_size(struct perf_session *session)
92 machines__set_id_hdr_size(&session->machines, id_hdr_size); 53 machines__set_id_hdr_size(&session->machines, id_hdr_size);
93} 54}
94 55
95int perf_session__create_kernel_maps(struct perf_session *self) 56int perf_session__create_kernel_maps(struct perf_session *session)
96{ 57{
97 int ret = machine__create_kernel_maps(&self->machines.host); 58 int ret = machine__create_kernel_maps(&session->machines.host);
98 59
99 if (ret >= 0) 60 if (ret >= 0)
100 ret = machines__create_guest_kernel_maps(&self->machines); 61 ret = machines__create_guest_kernel_maps(&session->machines);
101 return ret; 62 return ret;
102} 63}
103 64
104static void perf_session__destroy_kernel_maps(struct perf_session *self) 65static void perf_session__destroy_kernel_maps(struct perf_session *session)
105{ 66{
106 machines__destroy_kernel_maps(&self->machines); 67 machines__destroy_kernel_maps(&session->machines);
107} 68}
108 69
109struct perf_session *perf_session__new(const char *filename, int mode, 70struct perf_session *perf_session__new(struct perf_data_file *file,
110 bool force, bool repipe, 71 bool repipe, struct perf_tool *tool)
111 struct perf_tool *tool)
112{ 72{
113 struct perf_session *self; 73 struct perf_session *session = zalloc(sizeof(*session));
114 struct stat st;
115 size_t len;
116
117 if (!filename || !strlen(filename)) {
118 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
119 filename = "-";
120 else
121 filename = "perf.data";
122 }
123 74
124 len = strlen(filename); 75 if (!session)
125 self = zalloc(sizeof(*self) + len);
126
127 if (self == NULL)
128 goto out; 76 goto out;
129 77
130 memcpy(self->filename, filename, len); 78 session->repipe = repipe;
131 self->repipe = repipe; 79 INIT_LIST_HEAD(&session->ordered_samples.samples);
132 INIT_LIST_HEAD(&self->ordered_samples.samples); 80 INIT_LIST_HEAD(&session->ordered_samples.sample_cache);
133 INIT_LIST_HEAD(&self->ordered_samples.sample_cache); 81 INIT_LIST_HEAD(&session->ordered_samples.to_free);
134 INIT_LIST_HEAD(&self->ordered_samples.to_free); 82 machines__init(&session->machines);
135 machines__init(&self->machines);
136 83
137 if (mode == O_RDONLY) { 84 if (file) {
138 if (perf_session__open(self, force) < 0) 85 if (perf_data_file__open(file))
139 goto out_delete; 86 goto out_delete;
140 perf_session__set_id_hdr_size(self); 87
141 } else if (mode == O_WRONLY) { 88 session->file = file;
89
90 if (perf_data_file__is_read(file)) {
91 if (perf_session__open(session) < 0)
92 goto out_close;
93
94 perf_session__set_id_hdr_size(session);
95 }
96 }
97
98 if (!file || perf_data_file__is_write(file)) {
142 /* 99 /*
143 * In O_RDONLY mode this will be performed when reading the 100 * In O_RDONLY mode this will be performed when reading the
144 * kernel MMAP event, in perf_event__process_mmap(). 101 * kernel MMAP event, in perf_event__process_mmap().
145 */ 102 */
146 if (perf_session__create_kernel_maps(self) < 0) 103 if (perf_session__create_kernel_maps(session) < 0)
147 goto out_delete; 104 goto out_delete;
148 } 105 }
149 106
150 if (tool && tool->ordering_requires_timestamps && 107 if (tool && tool->ordering_requires_timestamps &&
151 tool->ordered_samples && !perf_evlist__sample_id_all(self->evlist)) { 108 tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) {
152 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); 109 dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
153 tool->ordered_samples = false; 110 tool->ordered_samples = false;
154 } 111 }
155 112
156out: 113 return session;
157 return self; 114
158out_delete: 115 out_close:
159 perf_session__delete(self); 116 perf_data_file__close(file);
117 out_delete:
118 perf_session__delete(session);
119 out:
160 return NULL; 120 return NULL;
161} 121}
162 122
@@ -186,15 +146,16 @@ static void perf_session_env__delete(struct perf_session_env *env)
186 free(env->pmu_mappings); 146 free(env->pmu_mappings);
187} 147}
188 148
189void perf_session__delete(struct perf_session *self) 149void perf_session__delete(struct perf_session *session)
190{ 150{
191 perf_session__destroy_kernel_maps(self); 151 perf_session__destroy_kernel_maps(session);
192 perf_session__delete_dead_threads(self); 152 perf_session__delete_dead_threads(session);
193 perf_session__delete_threads(self); 153 perf_session__delete_threads(session);
194 perf_session_env__delete(&self->header.env); 154 perf_session_env__delete(&session->header.env);
195 machines__exit(&self->machines); 155 machines__exit(&session->machines);
196 close(self->fd); 156 if (session->file)
197 free(self); 157 perf_data_file__close(session->file);
158 free(session);
198 vdso__exit(); 159 vdso__exit();
199} 160}
200 161
@@ -397,6 +358,17 @@ static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
397 swap_sample_id_all(event, &event->read + 1); 358 swap_sample_id_all(event, &event->read + 1);
398} 359}
399 360
361static void perf_event__throttle_swap(union perf_event *event,
362 bool sample_id_all)
363{
364 event->throttle.time = bswap_64(event->throttle.time);
365 event->throttle.id = bswap_64(event->throttle.id);
366 event->throttle.stream_id = bswap_64(event->throttle.stream_id);
367
368 if (sample_id_all)
369 swap_sample_id_all(event, &event->throttle + 1);
370}
371
400static u8 revbyte(u8 b) 372static u8 revbyte(u8 b)
401{ 373{
402 int rev = (b >> 4) | ((b & 0xf) << 4); 374 int rev = (b >> 4) | ((b & 0xf) << 4);
@@ -442,6 +414,9 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
442 attr->bp_type = bswap_32(attr->bp_type); 414 attr->bp_type = bswap_32(attr->bp_type);
443 attr->bp_addr = bswap_64(attr->bp_addr); 415 attr->bp_addr = bswap_64(attr->bp_addr);
444 attr->bp_len = bswap_64(attr->bp_len); 416 attr->bp_len = bswap_64(attr->bp_len);
417 attr->branch_sample_type = bswap_64(attr->branch_sample_type);
418 attr->sample_regs_user = bswap_64(attr->sample_regs_user);
419 attr->sample_stack_user = bswap_32(attr->sample_stack_user);
445 420
446 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); 421 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
447} 422}
@@ -482,6 +457,8 @@ static perf_event__swap_op perf_event__swap_ops[] = {
482 [PERF_RECORD_EXIT] = perf_event__task_swap, 457 [PERF_RECORD_EXIT] = perf_event__task_swap,
483 [PERF_RECORD_LOST] = perf_event__all64_swap, 458 [PERF_RECORD_LOST] = perf_event__all64_swap,
484 [PERF_RECORD_READ] = perf_event__read_swap, 459 [PERF_RECORD_READ] = perf_event__read_swap,
460 [PERF_RECORD_THROTTLE] = perf_event__throttle_swap,
461 [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap,
485 [PERF_RECORD_SAMPLE] = perf_event__all64_swap, 462 [PERF_RECORD_SAMPLE] = perf_event__all64_swap,
486 [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, 463 [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap,
487 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, 464 [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
@@ -525,13 +502,16 @@ static int flush_sample_queue(struct perf_session *s,
525 struct perf_sample sample; 502 struct perf_sample sample;
526 u64 limit = os->next_flush; 503 u64 limit = os->next_flush;
527 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; 504 u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
528 unsigned idx = 0, progress_next = os->nr_samples / 16;
529 bool show_progress = limit == ULLONG_MAX; 505 bool show_progress = limit == ULLONG_MAX;
506 struct ui_progress prog;
530 int ret; 507 int ret;
531 508
532 if (!tool->ordered_samples || !limit) 509 if (!tool->ordered_samples || !limit)
533 return 0; 510 return 0;
534 511
512 if (show_progress)
513 ui_progress__init(&prog, os->nr_samples, "Processing time ordered events...");
514
535 list_for_each_entry_safe(iter, tmp, head, list) { 515 list_for_each_entry_safe(iter, tmp, head, list) {
536 if (session_done()) 516 if (session_done())
537 return 0; 517 return 0;
@@ -552,11 +532,9 @@ static int flush_sample_queue(struct perf_session *s,
552 os->last_flush = iter->timestamp; 532 os->last_flush = iter->timestamp;
553 list_del(&iter->list); 533 list_del(&iter->list);
554 list_add(&iter->list, &os->sample_cache); 534 list_add(&iter->list, &os->sample_cache);
555 if (show_progress && (++idx >= progress_next)) { 535
556 progress_next += os->nr_samples / 16; 536 if (show_progress)
557 ui_progress__update(idx, os->nr_samples, 537 ui_progress__update(&prog, 1);
558 "Processing time ordered events...");
559 }
560 } 538 }
561 539
562 if (list_empty(head)) { 540 if (list_empty(head)) {
@@ -860,6 +838,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
860 if (sample_type & PERF_SAMPLE_DATA_SRC) 838 if (sample_type & PERF_SAMPLE_DATA_SRC)
861 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src); 839 printf(" . data_src: 0x%"PRIx64"\n", sample->data_src);
862 840
841 if (sample_type & PERF_SAMPLE_TRANSACTION)
842 printf("... transaction: %" PRIx64 "\n", sample->transaction);
843
863 if (sample_type & PERF_SAMPLE_READ) 844 if (sample_type & PERF_SAMPLE_READ)
864 sample_read__printf(sample, evsel->attr.read_format); 845 sample_read__printf(sample, evsel->attr.read_format);
865} 846}
@@ -1031,6 +1012,7 @@ static int perf_session_deliver_event(struct perf_session *session,
1031static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 1012static int perf_session__process_user_event(struct perf_session *session, union perf_event *event,
1032 struct perf_tool *tool, u64 file_offset) 1013 struct perf_tool *tool, u64 file_offset)
1033{ 1014{
1015 int fd = perf_data_file__fd(session->file);
1034 int err; 1016 int err;
1035 1017
1036 dump_event(session, event, file_offset, NULL); 1018 dump_event(session, event, file_offset, NULL);
@@ -1044,7 +1026,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
1044 return err; 1026 return err;
1045 case PERF_RECORD_HEADER_TRACING_DATA: 1027 case PERF_RECORD_HEADER_TRACING_DATA:
1046 /* setup for reading amidst mmap */ 1028 /* setup for reading amidst mmap */
1047 lseek(session->fd, file_offset, SEEK_SET); 1029 lseek(fd, file_offset, SEEK_SET);
1048 return tool->tracing_data(tool, event, session); 1030 return tool->tracing_data(tool, event, session);
1049 case PERF_RECORD_HEADER_BUILD_ID: 1031 case PERF_RECORD_HEADER_BUILD_ID:
1050 return tool->build_id(tool, event, session); 1032 return tool->build_id(tool, event, session);
@@ -1101,11 +1083,11 @@ static int perf_session__process_event(struct perf_session *session,
1101 file_offset); 1083 file_offset);
1102} 1084}
1103 1085
1104void perf_event_header__bswap(struct perf_event_header *self) 1086void perf_event_header__bswap(struct perf_event_header *hdr)
1105{ 1087{
1106 self->type = bswap_32(self->type); 1088 hdr->type = bswap_32(hdr->type);
1107 self->misc = bswap_16(self->misc); 1089 hdr->misc = bswap_16(hdr->misc);
1108 self->size = bswap_16(self->size); 1090 hdr->size = bswap_16(hdr->size);
1109} 1091}
1110 1092
1111struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1093struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
@@ -1113,11 +1095,11 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1113 return machine__findnew_thread(&session->machines.host, 0, pid); 1095 return machine__findnew_thread(&session->machines.host, 0, pid);
1114} 1096}
1115 1097
1116static struct thread *perf_session__register_idle_thread(struct perf_session *self) 1098static struct thread *perf_session__register_idle_thread(struct perf_session *session)
1117{ 1099{
1118 struct thread *thread = perf_session__findnew(self, 0); 1100 struct thread *thread = perf_session__findnew(session, 0);
1119 1101
1120 if (thread == NULL || thread__set_comm(thread, "swapper")) { 1102 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
1121 pr_err("problem inserting idle task.\n"); 1103 pr_err("problem inserting idle task.\n");
1122 thread = NULL; 1104 thread = NULL;
1123 } 1105 }
@@ -1167,9 +1149,10 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
1167 1149
1168volatile int session_done; 1150volatile int session_done;
1169 1151
1170static int __perf_session__process_pipe_events(struct perf_session *self, 1152static int __perf_session__process_pipe_events(struct perf_session *session,
1171 struct perf_tool *tool) 1153 struct perf_tool *tool)
1172{ 1154{
1155 int fd = perf_data_file__fd(session->file);
1173 union perf_event *event; 1156 union perf_event *event;
1174 uint32_t size, cur_size = 0; 1157 uint32_t size, cur_size = 0;
1175 void *buf = NULL; 1158 void *buf = NULL;
@@ -1188,7 +1171,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
1188 return -errno; 1171 return -errno;
1189more: 1172more:
1190 event = buf; 1173 event = buf;
1191 err = readn(self->fd, event, sizeof(struct perf_event_header)); 1174 err = readn(fd, event, sizeof(struct perf_event_header));
1192 if (err <= 0) { 1175 if (err <= 0) {
1193 if (err == 0) 1176 if (err == 0)
1194 goto done; 1177 goto done;
@@ -1197,7 +1180,7 @@ more:
1197 goto out_err; 1180 goto out_err;
1198 } 1181 }
1199 1182
1200 if (self->header.needs_swap) 1183 if (session->header.needs_swap)
1201 perf_event_header__bswap(&event->header); 1184 perf_event_header__bswap(&event->header);
1202 1185
1203 size = event->header.size; 1186 size = event->header.size;
@@ -1220,7 +1203,7 @@ more:
1220 p += sizeof(struct perf_event_header); 1203 p += sizeof(struct perf_event_header);
1221 1204
1222 if (size - sizeof(struct perf_event_header)) { 1205 if (size - sizeof(struct perf_event_header)) {
1223 err = readn(self->fd, p, size - sizeof(struct perf_event_header)); 1206 err = readn(fd, p, size - sizeof(struct perf_event_header));
1224 if (err <= 0) { 1207 if (err <= 0) {
1225 if (err == 0) { 1208 if (err == 0) {
1226 pr_err("unexpected end of event stream\n"); 1209 pr_err("unexpected end of event stream\n");
@@ -1232,7 +1215,7 @@ more:
1232 } 1215 }
1233 } 1216 }
1234 1217
1235 if ((skip = perf_session__process_event(self, event, tool, head)) < 0) { 1218 if ((skip = perf_session__process_event(session, event, tool, head)) < 0) {
1236 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1219 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1237 head, event->header.size, event->header.type); 1220 head, event->header.size, event->header.type);
1238 err = -EINVAL; 1221 err = -EINVAL;
@@ -1247,11 +1230,13 @@ more:
1247 if (!session_done()) 1230 if (!session_done())
1248 goto more; 1231 goto more;
1249done: 1232done:
1250 err = 0; 1233 /* do the final flush for ordered samples */
1234 session->ordered_samples.next_flush = ULLONG_MAX;
1235 err = flush_sample_queue(session, tool);
1251out_err: 1236out_err:
1252 free(buf); 1237 free(buf);
1253 perf_session__warn_about_errors(self, tool); 1238 perf_session__warn_about_errors(session, tool);
1254 perf_session_free_sample_buffers(self); 1239 perf_session_free_sample_buffers(session);
1255 return err; 1240 return err;
1256} 1241}
1257 1242
@@ -1299,12 +1284,14 @@ int __perf_session__process_events(struct perf_session *session,
1299 u64 data_offset, u64 data_size, 1284 u64 data_offset, u64 data_size,
1300 u64 file_size, struct perf_tool *tool) 1285 u64 file_size, struct perf_tool *tool)
1301{ 1286{
1302 u64 head, page_offset, file_offset, file_pos, progress_next; 1287 int fd = perf_data_file__fd(session->file);
1288 u64 head, page_offset, file_offset, file_pos;
1303 int err, mmap_prot, mmap_flags, map_idx = 0; 1289 int err, mmap_prot, mmap_flags, map_idx = 0;
1304 size_t mmap_size; 1290 size_t mmap_size;
1305 char *buf, *mmaps[NUM_MMAPS]; 1291 char *buf, *mmaps[NUM_MMAPS];
1306 union perf_event *event; 1292 union perf_event *event;
1307 uint32_t size; 1293 uint32_t size;
1294 struct ui_progress prog;
1308 1295
1309 perf_tool__fill_defaults(tool); 1296 perf_tool__fill_defaults(tool);
1310 1297
@@ -1315,7 +1302,7 @@ int __perf_session__process_events(struct perf_session *session,
1315 if (data_size && (data_offset + data_size < file_size)) 1302 if (data_size && (data_offset + data_size < file_size))
1316 file_size = data_offset + data_size; 1303 file_size = data_offset + data_size;
1317 1304
1318 progress_next = file_size / 16; 1305 ui_progress__init(&prog, file_size, "Processing events...");
1319 1306
1320 mmap_size = MMAP_SIZE; 1307 mmap_size = MMAP_SIZE;
1321 if (mmap_size > file_size) 1308 if (mmap_size > file_size)
@@ -1331,7 +1318,7 @@ int __perf_session__process_events(struct perf_session *session,
1331 mmap_flags = MAP_PRIVATE; 1318 mmap_flags = MAP_PRIVATE;
1332 } 1319 }
1333remap: 1320remap:
1334 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, session->fd, 1321 buf = mmap(NULL, mmap_size, mmap_prot, mmap_flags, fd,
1335 file_offset); 1322 file_offset);
1336 if (buf == MAP_FAILED) { 1323 if (buf == MAP_FAILED) {
1337 pr_err("failed to mmap file\n"); 1324 pr_err("failed to mmap file\n");
@@ -1370,19 +1357,15 @@ more:
1370 head += size; 1357 head += size;
1371 file_pos += size; 1358 file_pos += size;
1372 1359
1373 if (file_pos >= progress_next) { 1360 ui_progress__update(&prog, size);
1374 progress_next += file_size / 16;
1375 ui_progress__update(file_pos, file_size,
1376 "Processing events...");
1377 }
1378 1361
1379 err = 0;
1380 if (session_done()) 1362 if (session_done())
1381 goto out_err; 1363 goto out;
1382 1364
1383 if (file_pos < file_size) 1365 if (file_pos < file_size)
1384 goto more; 1366 goto more;
1385 1367
1368out:
1386 /* do the final flush for ordered samples */ 1369 /* do the final flush for ordered samples */
1387 session->ordered_samples.next_flush = ULLONG_MAX; 1370 session->ordered_samples.next_flush = ULLONG_MAX;
1388 err = flush_sample_queue(session, tool); 1371 err = flush_sample_queue(session, tool);
@@ -1393,21 +1376,22 @@ out_err:
1393 return err; 1376 return err;
1394} 1377}
1395 1378
1396int perf_session__process_events(struct perf_session *self, 1379int perf_session__process_events(struct perf_session *session,
1397 struct perf_tool *tool) 1380 struct perf_tool *tool)
1398{ 1381{
1382 u64 size = perf_data_file__size(session->file);
1399 int err; 1383 int err;
1400 1384
1401 if (perf_session__register_idle_thread(self) == NULL) 1385 if (perf_session__register_idle_thread(session) == NULL)
1402 return -ENOMEM; 1386 return -ENOMEM;
1403 1387
1404 if (!self->fd_pipe) 1388 if (!perf_data_file__is_pipe(session->file))
1405 err = __perf_session__process_events(self, 1389 err = __perf_session__process_events(session,
1406 self->header.data_offset, 1390 session->header.data_offset,
1407 self->header.data_size, 1391 session->header.data_size,
1408 self->size, tool); 1392 size, tool);
1409 else 1393 else
1410 err = __perf_session__process_pipe_events(self, tool); 1394 err = __perf_session__process_pipe_events(session, tool);
1411 1395
1412 return err; 1396 return err;
1413} 1397}
@@ -1456,15 +1440,15 @@ int maps__set_kallsyms_ref_reloc_sym(struct map **maps,
1456 return 0; 1440 return 0;
1457} 1441}
1458 1442
1459size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp) 1443size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp)
1460{ 1444{
1461 return machines__fprintf_dsos(&self->machines, fp); 1445 return machines__fprintf_dsos(&session->machines, fp);
1462} 1446}
1463 1447
1464size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp, 1448size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
1465 bool (skip)(struct dso *dso, int parm), int parm) 1449 bool (skip)(struct dso *dso, int parm), int parm)
1466{ 1450{
1467 return machines__fprintf_dsos_buildid(&self->machines, fp, skip, parm); 1451 return machines__fprintf_dsos_buildid(&session->machines, fp, skip, parm);
1468} 1452}
1469 1453
1470size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) 1454size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
@@ -1525,7 +1509,8 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event,
1525 if (symbol_conf.use_callchain && sample->callchain) { 1509 if (symbol_conf.use_callchain && sample->callchain) {
1526 1510
1527 if (machine__resolve_callchain(machine, evsel, al.thread, 1511 if (machine__resolve_callchain(machine, evsel, al.thread,
1528 sample, NULL, NULL) != 0) { 1512 sample, NULL, NULL,
1513 PERF_MAX_STACK_DEPTH) != 0) {
1529 if (verbose) 1514 if (verbose)
1530 error("Failed to resolve callchain. Skipping\n"); 1515 error("Failed to resolve callchain. Skipping\n");
1531 return; 1516 return;
@@ -1629,13 +1614,14 @@ int perf_session__cpu_bitmap(struct perf_session *session,
1629void perf_session__fprintf_info(struct perf_session *session, FILE *fp, 1614void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1630 bool full) 1615 bool full)
1631{ 1616{
1617 int fd = perf_data_file__fd(session->file);
1632 struct stat st; 1618 struct stat st;
1633 int ret; 1619 int ret;
1634 1620
1635 if (session == NULL || fp == NULL) 1621 if (session == NULL || fp == NULL)
1636 return; 1622 return;
1637 1623
1638 ret = fstat(session->fd, &st); 1624 ret = fstat(fd, &st);
1639 if (ret == -1) 1625 if (ret == -1)
1640 return; 1626 return;
1641 1627
@@ -1664,9 +1650,9 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
1664 continue; 1650 continue;
1665 1651
1666 err = -EEXIST; 1652 err = -EEXIST;
1667 if (evsel->handler.func != NULL) 1653 if (evsel->handler != NULL)
1668 goto out; 1654 goto out;
1669 evsel->handler.func = assocs[i].handler; 1655 evsel->handler = assocs[i].handler;
1670 } 1656 }
1671 1657
1672 err = 0; 1658 err = 0;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 04bf7373a7e5..50f640958f0f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -7,6 +7,7 @@
7#include "machine.h" 7#include "machine.h"
8#include "symbol.h" 8#include "symbol.h"
9#include "thread.h" 9#include "thread.h"
10#include "data.h"
10#include <linux/rbtree.h> 11#include <linux/rbtree.h>
11#include <linux/perf_event.h> 12#include <linux/perf_event.h>
12 13
@@ -29,16 +30,13 @@ struct ordered_samples {
29 30
30struct perf_session { 31struct perf_session {
31 struct perf_header header; 32 struct perf_header header;
32 unsigned long size;
33 struct machines machines; 33 struct machines machines;
34 struct perf_evlist *evlist; 34 struct perf_evlist *evlist;
35 struct pevent *pevent; 35 struct pevent *pevent;
36 struct events_stats stats; 36 struct events_stats stats;
37 int fd;
38 bool fd_pipe;
39 bool repipe; 37 bool repipe;
40 struct ordered_samples ordered_samples; 38 struct ordered_samples ordered_samples;
41 char filename[1]; 39 struct perf_data_file *file;
42}; 40};
43 41
44#define PRINT_IP_OPT_IP (1<<0) 42#define PRINT_IP_OPT_IP (1<<0)
@@ -49,17 +47,16 @@ struct perf_session {
49 47
50struct perf_tool; 48struct perf_tool;
51 49
52struct perf_session *perf_session__new(const char *filename, int mode, 50struct perf_session *perf_session__new(struct perf_data_file *file,
53 bool force, bool repipe, 51 bool repipe, struct perf_tool *tool);
54 struct perf_tool *tool);
55void perf_session__delete(struct perf_session *session); 52void perf_session__delete(struct perf_session *session);
56 53
57void perf_event_header__bswap(struct perf_event_header *self); 54void perf_event_header__bswap(struct perf_event_header *hdr);
58 55
59int __perf_session__process_events(struct perf_session *self, 56int __perf_session__process_events(struct perf_session *session,
60 u64 data_offset, u64 data_size, u64 size, 57 u64 data_offset, u64 data_size, u64 size,
61 struct perf_tool *tool); 58 struct perf_tool *tool);
62int perf_session__process_events(struct perf_session *self, 59int perf_session__process_events(struct perf_session *session,
63 struct perf_tool *tool); 60 struct perf_tool *tool);
64 61
65int perf_session_queue_event(struct perf_session *s, union perf_event *event, 62int perf_session_queue_event(struct perf_session *s, union perf_event *event,
@@ -67,37 +64,38 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event,
67 64
68void perf_tool__fill_defaults(struct perf_tool *tool); 65void perf_tool__fill_defaults(struct perf_tool *tool);
69 66
70int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, 67int perf_session__resolve_callchain(struct perf_session *session,
68 struct perf_evsel *evsel,
71 struct thread *thread, 69 struct thread *thread,
72 struct ip_callchain *chain, 70 struct ip_callchain *chain,
73 struct symbol **parent); 71 struct symbol **parent);
74 72
75bool perf_session__has_traces(struct perf_session *self, const char *msg); 73bool perf_session__has_traces(struct perf_session *session, const char *msg);
76 74
77void mem_bswap_64(void *src, int byte_size); 75void mem_bswap_64(void *src, int byte_size);
78void mem_bswap_32(void *src, int byte_size); 76void mem_bswap_32(void *src, int byte_size);
79void perf_event__attr_swap(struct perf_event_attr *attr); 77void perf_event__attr_swap(struct perf_event_attr *attr);
80 78
81int perf_session__create_kernel_maps(struct perf_session *self); 79int perf_session__create_kernel_maps(struct perf_session *session);
82 80
83void perf_session__set_id_hdr_size(struct perf_session *session); 81void perf_session__set_id_hdr_size(struct perf_session *session);
84 82
85static inline 83static inline
86struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) 84struct machine *perf_session__find_machine(struct perf_session *session, pid_t pid)
87{ 85{
88 return machines__find(&self->machines, pid); 86 return machines__find(&session->machines, pid);
89} 87}
90 88
91static inline 89static inline
92struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid) 90struct machine *perf_session__findnew_machine(struct perf_session *session, pid_t pid)
93{ 91{
94 return machines__findnew(&self->machines, pid); 92 return machines__findnew(&session->machines, pid);
95} 93}
96 94
97struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); 95struct thread *perf_session__findnew(struct perf_session *session, pid_t pid);
98size_t perf_session__fprintf(struct perf_session *self, FILE *fp); 96size_t perf_session__fprintf(struct perf_session *session, FILE *fp);
99 97
100size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); 98size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp);
101 99
102size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp, 100size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
103 bool (fn)(struct dso *dso, int parm), int parm); 101 bool (fn)(struct dso *dso, int parm), int parm);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 5f118a089519..8b0bb1f4494a 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,5 +1,6 @@
1#include "sort.h" 1#include "sort.h"
2#include "hist.h" 2#include "hist.h"
3#include "comm.h"
3#include "symbol.h" 4#include "symbol.h"
4 5
5regex_t parent_regex; 6regex_t parent_regex;
@@ -42,7 +43,7 @@ static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
42 return n; 43 return n;
43} 44}
44 45
45static int64_t cmp_null(void *l, void *r) 46static int64_t cmp_null(const void *l, const void *r)
46{ 47{
47 if (!l && !r) 48 if (!l && !r)
48 return 0; 49 return 0;
@@ -60,11 +61,12 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
60 return right->thread->tid - left->thread->tid; 61 return right->thread->tid - left->thread->tid;
61} 62}
62 63
63static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 64static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
64 size_t size, unsigned int width) 65 size_t size, unsigned int width)
65{ 66{
67 const char *comm = thread__comm_str(he->thread);
66 return repsep_snprintf(bf, size, "%*s:%5d", width - 6, 68 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
67 self->thread->comm ?: "", self->thread->tid); 69 comm ?: "", he->thread->tid);
68} 70}
69 71
70struct sort_entry sort_thread = { 72struct sort_entry sort_thread = {
@@ -79,25 +81,21 @@ struct sort_entry sort_thread = {
79static int64_t 81static int64_t
80sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 82sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
81{ 83{
82 return right->thread->tid - left->thread->tid; 84 /* Compare the addr that should be unique among comm */
85 return comm__str(right->comm) - comm__str(left->comm);
83} 86}
84 87
85static int64_t 88static int64_t
86sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) 89sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
87{ 90{
88 char *comm_l = left->thread->comm; 91 /* Compare the addr that should be unique among comm */
89 char *comm_r = right->thread->comm; 92 return comm__str(right->comm) - comm__str(left->comm);
90
91 if (!comm_l || !comm_r)
92 return cmp_null(comm_l, comm_r);
93
94 return strcmp(comm_l, comm_r);
95} 93}
96 94
97static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, 95static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
98 size_t size, unsigned int width) 96 size_t size, unsigned int width)
99{ 97{
100 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); 98 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
101} 99}
102 100
103struct sort_entry sort_comm = { 101struct sort_entry sort_comm = {
@@ -148,10 +146,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf,
148 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); 146 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
149} 147}
150 148
151static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, 149static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
152 size_t size, unsigned int width) 150 size_t size, unsigned int width)
153{ 151{
154 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); 152 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
155} 153}
156 154
157struct sort_entry sort_dso = { 155struct sort_entry sort_dso = {
@@ -182,9 +180,19 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
182static int64_t 180static int64_t
183sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 181sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
184{ 182{
183 int64_t ret;
184
185 if (!left->ms.sym && !right->ms.sym) 185 if (!left->ms.sym && !right->ms.sym)
186 return right->level - left->level; 186 return right->level - left->level;
187 187
188 /*
189 * comparing symbol address alone is not enough since it's a
190 * relative address within a dso.
191 */
192 ret = sort__dso_cmp(left, right);
193 if (ret != 0)
194 return ret;
195
188 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 196 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
189} 197}
190 198
@@ -224,11 +232,11 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
224 return ret; 232 return ret;
225} 233}
226 234
227static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, 235static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
228 size_t size, unsigned int width) 236 size_t size, unsigned int width)
229{ 237{
230 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, 238 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
231 self->level, bf, size, width); 239 he->level, bf, size, width);
232} 240}
233 241
234struct sort_entry sort_sym = { 242struct sort_entry sort_sym = {
@@ -243,50 +251,32 @@ struct sort_entry sort_sym = {
243static int64_t 251static int64_t
244sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) 252sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
245{ 253{
246 return (int64_t)(right->ip - left->ip); 254 if (!left->srcline) {
255 if (!left->ms.map)
256 left->srcline = SRCLINE_UNKNOWN;
257 else {
258 struct map *map = left->ms.map;
259 left->srcline = get_srcline(map->dso,
260 map__rip_2objdump(map, left->ip));
261 }
262 }
263 if (!right->srcline) {
264 if (!right->ms.map)
265 right->srcline = SRCLINE_UNKNOWN;
266 else {
267 struct map *map = right->ms.map;
268 right->srcline = get_srcline(map->dso,
269 map__rip_2objdump(map, right->ip));
270 }
271 }
272 return strcmp(left->srcline, right->srcline);
247} 273}
248 274
249static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, 275static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
250 size_t size, 276 size_t size,
251 unsigned int width __maybe_unused) 277 unsigned int width __maybe_unused)
252{ 278{
253 FILE *fp = NULL; 279 return repsep_snprintf(bf, size, "%s", he->srcline);
254 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
255 size_t line_len;
256
257 if (path != NULL)
258 goto out_path;
259
260 if (!self->ms.map)
261 goto out_ip;
262
263 if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10))
264 goto out_ip;
265
266 snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
267 self->ms.map->dso->long_name, self->ip);
268 fp = popen(cmd, "r");
269 if (!fp)
270 goto out_ip;
271
272 if (getline(&path, &line_len, fp) < 0 || !line_len)
273 goto out_ip;
274 self->srcline = strdup(path);
275 if (self->srcline == NULL)
276 goto out_ip;
277
278 nl = strchr(self->srcline, '\n');
279 if (nl != NULL)
280 *nl = '\0';
281 path = self->srcline;
282out_path:
283 if (fp)
284 pclose(fp);
285 return repsep_snprintf(bf, size, "%s", path);
286out_ip:
287 if (fp)
288 pclose(fp);
289 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
290} 280}
291 281
292struct sort_entry sort_srcline = { 282struct sort_entry sort_srcline = {
@@ -310,11 +300,11 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
310 return strcmp(sym_l->name, sym_r->name); 300 return strcmp(sym_l->name, sym_r->name);
311} 301}
312 302
313static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, 303static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
314 size_t size, unsigned int width) 304 size_t size, unsigned int width)
315{ 305{
316 return repsep_snprintf(bf, size, "%-*s", width, 306 return repsep_snprintf(bf, size, "%-*s", width,
317 self->parent ? self->parent->name : "[other]"); 307 he->parent ? he->parent->name : "[other]");
318} 308}
319 309
320struct sort_entry sort_parent = { 310struct sort_entry sort_parent = {
@@ -332,10 +322,10 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
332 return right->cpu - left->cpu; 322 return right->cpu - left->cpu;
333} 323}
334 324
335static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, 325static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
336 size_t size, unsigned int width) 326 size_t size, unsigned int width)
337{ 327{
338 return repsep_snprintf(bf, size, "%*d", width, self->cpu); 328 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
339} 329}
340 330
341struct sort_entry sort_cpu = { 331struct sort_entry sort_cpu = {
@@ -354,10 +344,10 @@ sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
354 right->branch_info->from.map); 344 right->branch_info->from.map);
355} 345}
356 346
357static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf, 347static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
358 size_t size, unsigned int width) 348 size_t size, unsigned int width)
359{ 349{
360 return _hist_entry__dso_snprintf(self->branch_info->from.map, 350 return _hist_entry__dso_snprintf(he->branch_info->from.map,
361 bf, size, width); 351 bf, size, width);
362} 352}
363 353
@@ -368,10 +358,10 @@ sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
368 right->branch_info->to.map); 358 right->branch_info->to.map);
369} 359}
370 360
371static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf, 361static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
372 size_t size, unsigned int width) 362 size_t size, unsigned int width)
373{ 363{
374 return _hist_entry__dso_snprintf(self->branch_info->to.map, 364 return _hist_entry__dso_snprintf(he->branch_info->to.map,
375 bf, size, width); 365 bf, size, width);
376} 366}
377 367
@@ -399,21 +389,21 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
399 return _sort__sym_cmp(to_l->sym, to_r->sym); 389 return _sort__sym_cmp(to_l->sym, to_r->sym);
400} 390}
401 391
402static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, 392static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
403 size_t size, unsigned int width) 393 size_t size, unsigned int width)
404{ 394{
405 struct addr_map_symbol *from = &self->branch_info->from; 395 struct addr_map_symbol *from = &he->branch_info->from;
406 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, 396 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
407 self->level, bf, size, width); 397 he->level, bf, size, width);
408 398
409} 399}
410 400
411static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, 401static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
412 size_t size, unsigned int width) 402 size_t size, unsigned int width)
413{ 403{
414 struct addr_map_symbol *to = &self->branch_info->to; 404 struct addr_map_symbol *to = &he->branch_info->to;
415 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, 405 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
416 self->level, bf, size, width); 406 he->level, bf, size, width);
417 407
418} 408}
419 409
@@ -456,13 +446,13 @@ sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
456 return mp || p; 446 return mp || p;
457} 447}
458 448
459static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf, 449static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
460 size_t size, unsigned int width){ 450 size_t size, unsigned int width){
461 static const char *out = "N/A"; 451 static const char *out = "N/A";
462 452
463 if (self->branch_info->flags.predicted) 453 if (he->branch_info->flags.predicted)
464 out = "N"; 454 out = "N";
465 else if (self->branch_info->flags.mispred) 455 else if (he->branch_info->flags.mispred)
466 out = "Y"; 456 out = "Y";
467 457
468 return repsep_snprintf(bf, size, "%-*s", width, out); 458 return repsep_snprintf(bf, size, "%-*s", width, out);
@@ -482,19 +472,19 @@ sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
482 return (int64_t)(r - l); 472 return (int64_t)(r - l);
483} 473}
484 474
485static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf, 475static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
486 size_t size, unsigned int width) 476 size_t size, unsigned int width)
487{ 477{
488 uint64_t addr = 0; 478 uint64_t addr = 0;
489 struct map *map = NULL; 479 struct map *map = NULL;
490 struct symbol *sym = NULL; 480 struct symbol *sym = NULL;
491 481
492 if (self->mem_info) { 482 if (he->mem_info) {
493 addr = self->mem_info->daddr.addr; 483 addr = he->mem_info->daddr.addr;
494 map = self->mem_info->daddr.map; 484 map = he->mem_info->daddr.map;
495 sym = self->mem_info->daddr.sym; 485 sym = he->mem_info->daddr.sym;
496 } 486 }
497 return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size, 487 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
498 width); 488 width);
499} 489}
500 490
@@ -512,13 +502,13 @@ sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
512 return _sort__dso_cmp(map_l, map_r); 502 return _sort__dso_cmp(map_l, map_r);
513} 503}
514 504
515static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf, 505static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
516 size_t size, unsigned int width) 506 size_t size, unsigned int width)
517{ 507{
518 struct map *map = NULL; 508 struct map *map = NULL;
519 509
520 if (self->mem_info) 510 if (he->mem_info)
521 map = self->mem_info->daddr.map; 511 map = he->mem_info->daddr.map;
522 512
523 return _hist_entry__dso_snprintf(map, bf, size, width); 513 return _hist_entry__dso_snprintf(map, bf, size, width);
524} 514}
@@ -542,14 +532,14 @@ sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
542 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); 532 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
543} 533}
544 534
545static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf, 535static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
546 size_t size, unsigned int width) 536 size_t size, unsigned int width)
547{ 537{
548 const char *out; 538 const char *out;
549 u64 mask = PERF_MEM_LOCK_NA; 539 u64 mask = PERF_MEM_LOCK_NA;
550 540
551 if (self->mem_info) 541 if (he->mem_info)
552 mask = self->mem_info->data_src.mem_lock; 542 mask = he->mem_info->data_src.mem_lock;
553 543
554 if (mask & PERF_MEM_LOCK_NA) 544 if (mask & PERF_MEM_LOCK_NA)
555 out = "N/A"; 545 out = "N/A";
@@ -591,7 +581,7 @@ static const char * const tlb_access[] = {
591}; 581};
592#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *)) 582#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
593 583
594static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf, 584static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
595 size_t size, unsigned int width) 585 size_t size, unsigned int width)
596{ 586{
597 char out[64]; 587 char out[64];
@@ -602,8 +592,8 @@ static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
602 592
603 out[0] = '\0'; 593 out[0] = '\0';
604 594
605 if (self->mem_info) 595 if (he->mem_info)
606 m = self->mem_info->data_src.mem_dtlb; 596 m = he->mem_info->data_src.mem_dtlb;
607 597
608 hit = m & PERF_MEM_TLB_HIT; 598 hit = m & PERF_MEM_TLB_HIT;
609 miss = m & PERF_MEM_TLB_MISS; 599 miss = m & PERF_MEM_TLB_MISS;
@@ -668,7 +658,7 @@ static const char * const mem_lvl[] = {
668}; 658};
669#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *)) 659#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
670 660
671static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf, 661static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
672 size_t size, unsigned int width) 662 size_t size, unsigned int width)
673{ 663{
674 char out[64]; 664 char out[64];
@@ -677,8 +667,8 @@ static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
677 u64 m = PERF_MEM_LVL_NA; 667 u64 m = PERF_MEM_LVL_NA;
678 u64 hit, miss; 668 u64 hit, miss;
679 669
680 if (self->mem_info) 670 if (he->mem_info)
681 m = self->mem_info->data_src.mem_lvl; 671 m = he->mem_info->data_src.mem_lvl;
682 672
683 out[0] = '\0'; 673 out[0] = '\0';
684 674
@@ -736,7 +726,7 @@ static const char * const snoop_access[] = {
736}; 726};
737#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *)) 727#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
738 728
739static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf, 729static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
740 size_t size, unsigned int width) 730 size_t size, unsigned int width)
741{ 731{
742 char out[64]; 732 char out[64];
@@ -746,8 +736,8 @@ static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
746 736
747 out[0] = '\0'; 737 out[0] = '\0';
748 738
749 if (self->mem_info) 739 if (he->mem_info)
750 m = self->mem_info->data_src.mem_snoop; 740 m = he->mem_info->data_src.mem_snoop;
751 741
752 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { 742 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
753 if (!(m & 0x1)) 743 if (!(m & 0x1))
@@ -784,10 +774,10 @@ sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
784 return he_weight(left) - he_weight(right); 774 return he_weight(left) - he_weight(right);
785} 775}
786 776
787static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf, 777static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
788 size_t size, unsigned int width) 778 size_t size, unsigned int width)
789{ 779{
790 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self)); 780 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
791} 781}
792 782
793struct sort_entry sort_local_weight = { 783struct sort_entry sort_local_weight = {
@@ -803,10 +793,10 @@ sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
803 return left->stat.weight - right->stat.weight; 793 return left->stat.weight - right->stat.weight;
804} 794}
805 795
806static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf, 796static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
807 size_t size, unsigned int width) 797 size_t size, unsigned int width)
808{ 798{
809 return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight); 799 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
810} 800}
811 801
812struct sort_entry sort_global_weight = { 802struct sort_entry sort_global_weight = {
@@ -858,6 +848,127 @@ struct sort_entry sort_mem_snoop = {
858 .se_width_idx = HISTC_MEM_SNOOP, 848 .se_width_idx = HISTC_MEM_SNOOP,
859}; 849};
860 850
851static int64_t
852sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
853{
854 return left->branch_info->flags.abort !=
855 right->branch_info->flags.abort;
856}
857
858static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
859 size_t size, unsigned int width)
860{
861 static const char *out = ".";
862
863 if (he->branch_info->flags.abort)
864 out = "A";
865 return repsep_snprintf(bf, size, "%-*s", width, out);
866}
867
868struct sort_entry sort_abort = {
869 .se_header = "Transaction abort",
870 .se_cmp = sort__abort_cmp,
871 .se_snprintf = hist_entry__abort_snprintf,
872 .se_width_idx = HISTC_ABORT,
873};
874
875static int64_t
876sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
877{
878 return left->branch_info->flags.in_tx !=
879 right->branch_info->flags.in_tx;
880}
881
882static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
883 size_t size, unsigned int width)
884{
885 static const char *out = ".";
886
887 if (he->branch_info->flags.in_tx)
888 out = "T";
889
890 return repsep_snprintf(bf, size, "%-*s", width, out);
891}
892
893struct sort_entry sort_in_tx = {
894 .se_header = "Branch in transaction",
895 .se_cmp = sort__in_tx_cmp,
896 .se_snprintf = hist_entry__in_tx_snprintf,
897 .se_width_idx = HISTC_IN_TX,
898};
899
900static int64_t
901sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
902{
903 return left->transaction - right->transaction;
904}
905
906static inline char *add_str(char *p, const char *str)
907{
908 strcpy(p, str);
909 return p + strlen(str);
910}
911
912static struct txbit {
913 unsigned flag;
914 const char *name;
915 int skip_for_len;
916} txbits[] = {
917 { PERF_TXN_ELISION, "EL ", 0 },
918 { PERF_TXN_TRANSACTION, "TX ", 1 },
919 { PERF_TXN_SYNC, "SYNC ", 1 },
920 { PERF_TXN_ASYNC, "ASYNC ", 0 },
921 { PERF_TXN_RETRY, "RETRY ", 0 },
922 { PERF_TXN_CONFLICT, "CON ", 0 },
923 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
924 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
925 { 0, NULL, 0 }
926};
927
928int hist_entry__transaction_len(void)
929{
930 int i;
931 int len = 0;
932
933 for (i = 0; txbits[i].name; i++) {
934 if (!txbits[i].skip_for_len)
935 len += strlen(txbits[i].name);
936 }
937 len += 4; /* :XX<space> */
938 return len;
939}
940
941static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
942 size_t size, unsigned int width)
943{
944 u64 t = he->transaction;
945 char buf[128];
946 char *p = buf;
947 int i;
948
949 buf[0] = 0;
950 for (i = 0; txbits[i].name; i++)
951 if (txbits[i].flag & t)
952 p = add_str(p, txbits[i].name);
953 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
954 p = add_str(p, "NEITHER ");
955 if (t & PERF_TXN_ABORT_MASK) {
956 sprintf(p, ":%" PRIx64,
957 (t & PERF_TXN_ABORT_MASK) >>
958 PERF_TXN_ABORT_SHIFT);
959 p += strlen(p);
960 }
961
962 return repsep_snprintf(bf, size, "%-*s", width, buf);
963}
964
965struct sort_entry sort_transaction = {
966 .se_header = "Transaction ",
967 .se_cmp = sort__transaction_cmp,
968 .se_snprintf = hist_entry__transaction_snprintf,
969 .se_width_idx = HISTC_TRANSACTION,
970};
971
861struct sort_dimension { 972struct sort_dimension {
862 const char *name; 973 const char *name;
863 struct sort_entry *entry; 974 struct sort_entry *entry;
@@ -876,6 +987,7 @@ static struct sort_dimension common_sort_dimensions[] = {
876 DIM(SORT_SRCLINE, "srcline", sort_srcline), 987 DIM(SORT_SRCLINE, "srcline", sort_srcline),
877 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 988 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
878 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 989 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
990 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
879}; 991};
880 992
881#undef DIM 993#undef DIM
@@ -888,6 +1000,8 @@ static struct sort_dimension bstack_sort_dimensions[] = {
888 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from), 1000 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
889 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to), 1001 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
890 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), 1002 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
1003 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1004 DIM(SORT_ABORT, "abort", sort_abort),
891}; 1005};
892 1006
893#undef DIM 1007#undef DIM
@@ -1009,7 +1123,7 @@ int setup_sorting(void)
1009 return ret; 1123 return ret;
1010} 1124}
1011 1125
1012static void sort_entry__setup_elide(struct sort_entry *self, 1126static void sort_entry__setup_elide(struct sort_entry *se,
1013 struct strlist *list, 1127 struct strlist *list,
1014 const char *list_name, FILE *fp) 1128 const char *list_name, FILE *fp)
1015{ 1129{
@@ -1017,12 +1131,14 @@ static void sort_entry__setup_elide(struct sort_entry *self,
1017 if (fp != NULL) 1131 if (fp != NULL)
1018 fprintf(fp, "# %s: %s\n", list_name, 1132 fprintf(fp, "# %s: %s\n", list_name,
1019 strlist__entry(list, 0)->s); 1133 strlist__entry(list, 0)->s);
1020 self->elide = true; 1134 se->elide = true;
1021 } 1135 }
1022} 1136}
1023 1137
1024void sort__setup_elide(FILE *output) 1138void sort__setup_elide(FILE *output)
1025{ 1139{
1140 struct sort_entry *se;
1141
1026 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, 1142 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1027 "dso", output); 1143 "dso", output);
1028 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, 1144 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
@@ -1058,4 +1174,15 @@ void sort__setup_elide(FILE *output)
1058 "snoop", output); 1174 "snoop", output);
1059 } 1175 }
1060 1176
1177 /*
1178 * It makes no sense to elide all of sort entries.
1179 * Just revert them to show up again.
1180 */
1181 list_for_each_entry(se, &hist_entry__sort_list, list) {
1182 if (!se->elide)
1183 return;
1184 }
1185
1186 list_for_each_entry(se, &hist_entry__sort_list, list)
1187 se->elide = false;
1061} 1188}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 4e80dbd271e7..43e5ff42a609 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -22,7 +22,6 @@
22#include "parse-events.h" 22#include "parse-events.h"
23 23
24#include "thread.h" 24#include "thread.h"
25#include "sort.h"
26 25
27extern regex_t parent_regex; 26extern regex_t parent_regex;
28extern const char *sort_order; 27extern const char *sort_order;
@@ -84,7 +83,9 @@ struct hist_entry {
84 struct he_stat stat; 83 struct he_stat stat;
85 struct map_symbol ms; 84 struct map_symbol ms;
86 struct thread *thread; 85 struct thread *thread;
86 struct comm *comm;
87 u64 ip; 87 u64 ip;
88 u64 transaction;
88 s32 cpu; 89 s32 cpu;
89 90
90 struct hist_entry_diff diff; 91 struct hist_entry_diff diff;
@@ -145,6 +146,7 @@ enum sort_type {
145 SORT_SRCLINE, 146 SORT_SRCLINE,
146 SORT_LOCAL_WEIGHT, 147 SORT_LOCAL_WEIGHT,
147 SORT_GLOBAL_WEIGHT, 148 SORT_GLOBAL_WEIGHT,
149 SORT_TRANSACTION,
148 150
149 /* branch stack specific sort keys */ 151 /* branch stack specific sort keys */
150 __SORT_BRANCH_STACK, 152 __SORT_BRANCH_STACK,
@@ -153,6 +155,8 @@ enum sort_type {
153 SORT_SYM_FROM, 155 SORT_SYM_FROM,
154 SORT_SYM_TO, 156 SORT_SYM_TO,
155 SORT_MISPREDICT, 157 SORT_MISPREDICT,
158 SORT_ABORT,
159 SORT_IN_TX,
156 160
157 /* memory mode specific sort keys */ 161 /* memory mode specific sort keys */
158 __SORT_MEMORY_MODE, 162 __SORT_MEMORY_MODE,
@@ -175,7 +179,7 @@ struct sort_entry {
175 179
176 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); 180 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
177 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); 181 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
178 int (*se_snprintf)(struct hist_entry *self, char *bf, size_t size, 182 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
179 unsigned int width); 183 unsigned int width);
180 u8 se_width_idx; 184 u8 se_width_idx;
181 bool elide; 185 bool elide;
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
new file mode 100644
index 000000000000..d11aefbc4b8d
--- /dev/null
+++ b/tools/perf/util/srcline.c
@@ -0,0 +1,265 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include <linux/kernel.h>
6
7#include "util/dso.h"
8#include "util/util.h"
9#include "util/debug.h"
10
11#ifdef HAVE_LIBBFD_SUPPORT
12
13/*
14 * Implement addr2line using libbfd.
15 */
16#define PACKAGE "perf"
17#include <bfd.h>
18
19struct a2l_data {
20 const char *input;
21 unsigned long addr;
22
23 bool found;
24 const char *filename;
25 const char *funcname;
26 unsigned line;
27
28 bfd *abfd;
29 asymbol **syms;
30};
31
32static int bfd_error(const char *string)
33{
34 const char *errmsg;
35
36 errmsg = bfd_errmsg(bfd_get_error());
37 fflush(stdout);
38
39 if (string)
40 pr_debug("%s: %s\n", string, errmsg);
41 else
42 pr_debug("%s\n", errmsg);
43
44 return -1;
45}
46
47static int slurp_symtab(bfd *abfd, struct a2l_data *a2l)
48{
49 long storage;
50 long symcount;
51 asymbol **syms;
52 bfd_boolean dynamic = FALSE;
53
54 if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
55 return bfd_error(bfd_get_filename(abfd));
56
57 storage = bfd_get_symtab_upper_bound(abfd);
58 if (storage == 0L) {
59 storage = bfd_get_dynamic_symtab_upper_bound(abfd);
60 dynamic = TRUE;
61 }
62 if (storage < 0L)
63 return bfd_error(bfd_get_filename(abfd));
64
65 syms = malloc(storage);
66 if (dynamic)
67 symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
68 else
69 symcount = bfd_canonicalize_symtab(abfd, syms);
70
71 if (symcount < 0) {
72 free(syms);
73 return bfd_error(bfd_get_filename(abfd));
74 }
75
76 a2l->syms = syms;
77 return 0;
78}
79
80static void find_address_in_section(bfd *abfd, asection *section, void *data)
81{
82 bfd_vma pc, vma;
83 bfd_size_type size;
84 struct a2l_data *a2l = data;
85
86 if (a2l->found)
87 return;
88
89 if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0)
90 return;
91
92 pc = a2l->addr;
93 vma = bfd_get_section_vma(abfd, section);
94 size = bfd_get_section_size(section);
95
96 if (pc < vma || pc >= vma + size)
97 return;
98
99 a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma,
100 &a2l->filename, &a2l->funcname,
101 &a2l->line);
102}
103
104static struct a2l_data *addr2line_init(const char *path)
105{
106 bfd *abfd;
107 struct a2l_data *a2l = NULL;
108
109 abfd = bfd_openr(path, NULL);
110 if (abfd == NULL)
111 return NULL;
112
113 if (!bfd_check_format(abfd, bfd_object))
114 goto out;
115
116 a2l = zalloc(sizeof(*a2l));
117 if (a2l == NULL)
118 goto out;
119
120 a2l->abfd = abfd;
121 a2l->input = strdup(path);
122 if (a2l->input == NULL)
123 goto out;
124
125 if (slurp_symtab(abfd, a2l))
126 goto out;
127
128 return a2l;
129
130out:
131 if (a2l) {
132 free((void *)a2l->input);
133 free(a2l);
134 }
135 bfd_close(abfd);
136 return NULL;
137}
138
139static void addr2line_cleanup(struct a2l_data *a2l)
140{
141 if (a2l->abfd)
142 bfd_close(a2l->abfd);
143 free((void *)a2l->input);
144 free(a2l->syms);
145 free(a2l);
146}
147
148static int addr2line(const char *dso_name, unsigned long addr,
149 char **file, unsigned int *line)
150{
151 int ret = 0;
152 struct a2l_data *a2l;
153
154 a2l = addr2line_init(dso_name);
155 if (a2l == NULL) {
156 pr_warning("addr2line_init failed for %s\n", dso_name);
157 return 0;
158 }
159
160 a2l->addr = addr;
161 bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
162
163 if (a2l->found && a2l->filename) {
164 *file = strdup(a2l->filename);
165 *line = a2l->line;
166
167 if (*file)
168 ret = 1;
169 }
170
171 addr2line_cleanup(a2l);
172 return ret;
173}
174
175#else /* HAVE_LIBBFD_SUPPORT */
176
177static int addr2line(const char *dso_name, unsigned long addr,
178 char **file, unsigned int *line_nr)
179{
180 FILE *fp;
181 char cmd[PATH_MAX];
182 char *filename = NULL;
183 size_t len;
184 char *sep;
185 int ret = 0;
186
187 scnprintf(cmd, sizeof(cmd), "addr2line -e %s %016"PRIx64,
188 dso_name, addr);
189
190 fp = popen(cmd, "r");
191 if (fp == NULL) {
192 pr_warning("popen failed for %s\n", dso_name);
193 return 0;
194 }
195
196 if (getline(&filename, &len, fp) < 0 || !len) {
197 pr_warning("addr2line has no output for %s\n", dso_name);
198 goto out;
199 }
200
201 sep = strchr(filename, '\n');
202 if (sep)
203 *sep = '\0';
204
205 if (!strcmp(filename, "??:0")) {
206 pr_debug("no debugging info in %s\n", dso_name);
207 free(filename);
208 goto out;
209 }
210
211 sep = strchr(filename, ':');
212 if (sep) {
213 *sep++ = '\0';
214 *file = filename;
215 *line_nr = strtoul(sep, NULL, 0);
216 ret = 1;
217 }
218out:
219 pclose(fp);
220 return ret;
221}
222#endif /* HAVE_LIBBFD_SUPPORT */
223
224char *get_srcline(struct dso *dso, unsigned long addr)
225{
226 char *file = NULL;
227 unsigned line = 0;
228 char *srcline;
229 char *dso_name = dso->long_name;
230 size_t size;
231
232 if (!dso->has_srcline)
233 return SRCLINE_UNKNOWN;
234
235 if (dso_name[0] == '[')
236 goto out;
237
238 if (!strncmp(dso_name, "/tmp/perf-", 10))
239 goto out;
240
241 if (!addr2line(dso_name, addr, &file, &line))
242 goto out;
243
244 /* just calculate actual length */
245 size = snprintf(NULL, 0, "%s:%u", file, line) + 1;
246
247 srcline = malloc(size);
248 if (srcline)
249 snprintf(srcline, size, "%s:%u", file, line);
250 else
251 srcline = SRCLINE_UNKNOWN;
252
253 free(file);
254 return srcline;
255
256out:
257 dso->has_srcline = 0;
258 return SRCLINE_UNKNOWN;
259}
260
261void free_srcline(char *srcline)
262{
263 if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0)
264 free(srcline);
265}
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c
index 834c8ebfe38e..3edd0538161f 100644
--- a/tools/perf/util/strfilter.c
+++ b/tools/perf/util/strfilter.c
@@ -10,22 +10,22 @@ static const char *OP_not = "!"; /* Logical NOT */
10#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!') 10#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!')
11#define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')') 11#define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')')
12 12
13static void strfilter_node__delete(struct strfilter_node *self) 13static void strfilter_node__delete(struct strfilter_node *node)
14{ 14{
15 if (self) { 15 if (node) {
16 if (self->p && !is_operator(*self->p)) 16 if (node->p && !is_operator(*node->p))
17 free((char *)self->p); 17 free((char *)node->p);
18 strfilter_node__delete(self->l); 18 strfilter_node__delete(node->l);
19 strfilter_node__delete(self->r); 19 strfilter_node__delete(node->r);
20 free(self); 20 free(node);
21 } 21 }
22} 22}
23 23
24void strfilter__delete(struct strfilter *self) 24void strfilter__delete(struct strfilter *filter)
25{ 25{
26 if (self) { 26 if (filter) {
27 strfilter_node__delete(self->root); 27 strfilter_node__delete(filter->root);
28 free(self); 28 free(filter);
29 } 29 }
30} 30}
31 31
@@ -62,15 +62,15 @@ static struct strfilter_node *strfilter_node__alloc(const char *op,
62 struct strfilter_node *l, 62 struct strfilter_node *l,
63 struct strfilter_node *r) 63 struct strfilter_node *r)
64{ 64{
65 struct strfilter_node *ret = zalloc(sizeof(struct strfilter_node)); 65 struct strfilter_node *node = zalloc(sizeof(*node));
66 66
67 if (ret) { 67 if (node) {
68 ret->p = op; 68 node->p = op;
69 ret->l = l; 69 node->l = l;
70 ret->r = r; 70 node->r = r;
71 } 71 }
72 72
73 return ret; 73 return node;
74} 74}
75 75
76static struct strfilter_node *strfilter_node__new(const char *s, 76static struct strfilter_node *strfilter_node__new(const char *s,
@@ -154,46 +154,46 @@ error:
154 */ 154 */
155struct strfilter *strfilter__new(const char *rules, const char **err) 155struct strfilter *strfilter__new(const char *rules, const char **err)
156{ 156{
157 struct strfilter *ret = zalloc(sizeof(struct strfilter)); 157 struct strfilter *filter = zalloc(sizeof(*filter));
158 const char *ep = NULL; 158 const char *ep = NULL;
159 159
160 if (ret) 160 if (filter)
161 ret->root = strfilter_node__new(rules, &ep); 161 filter->root = strfilter_node__new(rules, &ep);
162 162
163 if (!ret || !ret->root || *ep != '\0') { 163 if (!filter || !filter->root || *ep != '\0') {
164 if (err) 164 if (err)
165 *err = ep; 165 *err = ep;
166 strfilter__delete(ret); 166 strfilter__delete(filter);
167 ret = NULL; 167 filter = NULL;
168 } 168 }
169 169
170 return ret; 170 return filter;
171} 171}
172 172
173static bool strfilter_node__compare(struct strfilter_node *self, 173static bool strfilter_node__compare(struct strfilter_node *node,
174 const char *str) 174 const char *str)
175{ 175{
176 if (!self || !self->p) 176 if (!node || !node->p)
177 return false; 177 return false;
178 178
179 switch (*self->p) { 179 switch (*node->p) {
180 case '|': /* OR */ 180 case '|': /* OR */
181 return strfilter_node__compare(self->l, str) || 181 return strfilter_node__compare(node->l, str) ||
182 strfilter_node__compare(self->r, str); 182 strfilter_node__compare(node->r, str);
183 case '&': /* AND */ 183 case '&': /* AND */
184 return strfilter_node__compare(self->l, str) && 184 return strfilter_node__compare(node->l, str) &&
185 strfilter_node__compare(self->r, str); 185 strfilter_node__compare(node->r, str);
186 case '!': /* NOT */ 186 case '!': /* NOT */
187 return !strfilter_node__compare(self->r, str); 187 return !strfilter_node__compare(node->r, str);
188 default: 188 default:
189 return strglobmatch(str, self->p); 189 return strglobmatch(str, node->p);
190 } 190 }
191} 191}
192 192
193/* Return true if STR matches the filter rules */ 193/* Return true if STR matches the filter rules */
194bool strfilter__compare(struct strfilter *self, const char *str) 194bool strfilter__compare(struct strfilter *filter, const char *str)
195{ 195{
196 if (!self) 196 if (!filter)
197 return false; 197 return false;
198 return strfilter_node__compare(self->root, str); 198 return strfilter_node__compare(filter->root, str);
199} 199}
diff --git a/tools/perf/util/strfilter.h b/tools/perf/util/strfilter.h
index 00f58a7506de..fe611f3c9e39 100644
--- a/tools/perf/util/strfilter.h
+++ b/tools/perf/util/strfilter.h
@@ -30,19 +30,19 @@ struct strfilter *strfilter__new(const char *rules, const char **err);
30 30
31/** 31/**
32 * strfilter__compare - compare given string and a string filter 32 * strfilter__compare - compare given string and a string filter
33 * @self: String filter 33 * @filter: String filter
34 * @str: target string 34 * @str: target string
35 * 35 *
36 * Compare @str and @self. Return true if the str match the rule 36 * Compare @str and @filter. Return true if the str match the rule
37 */ 37 */
38bool strfilter__compare(struct strfilter *self, const char *str); 38bool strfilter__compare(struct strfilter *filter, const char *str);
39 39
40/** 40/**
41 * strfilter__delete - delete a string filter 41 * strfilter__delete - delete a string filter
42 * @self: String filter to delete 42 * @filter: String filter to delete
43 * 43 *
44 * Delete @self. 44 * Delete @filter.
45 */ 45 */
46void strfilter__delete(struct strfilter *self); 46void strfilter__delete(struct strfilter *filter);
47 47
48#endif 48#endif
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index a9c829be5216..eed0b96302af 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -8,7 +8,7 @@
8#include "symbol.h" 8#include "symbol.h"
9#include "debug.h" 9#include "debug.h"
10 10
11#ifndef HAVE_ELF_GETPHDRNUM 11#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
12static int elf_getphdrnum(Elf *elf, size_t *dst) 12static int elf_getphdrnum(Elf *elf, size_t *dst)
13{ 13{
14 GElf_Ehdr gehdr; 14 GElf_Ehdr gehdr;
@@ -487,27 +487,27 @@ int filename__read_debuglink(const char *filename, char *debuglink,
487 487
488 ek = elf_kind(elf); 488 ek = elf_kind(elf);
489 if (ek != ELF_K_ELF) 489 if (ek != ELF_K_ELF)
490 goto out_close; 490 goto out_elf_end;
491 491
492 if (gelf_getehdr(elf, &ehdr) == NULL) { 492 if (gelf_getehdr(elf, &ehdr) == NULL) {
493 pr_err("%s: cannot get elf header.\n", __func__); 493 pr_err("%s: cannot get elf header.\n", __func__);
494 goto out_close; 494 goto out_elf_end;
495 } 495 }
496 496
497 sec = elf_section_by_name(elf, &ehdr, &shdr, 497 sec = elf_section_by_name(elf, &ehdr, &shdr,
498 ".gnu_debuglink", NULL); 498 ".gnu_debuglink", NULL);
499 if (sec == NULL) 499 if (sec == NULL)
500 goto out_close; 500 goto out_elf_end;
501 501
502 data = elf_getdata(sec, NULL); 502 data = elf_getdata(sec, NULL);
503 if (data == NULL) 503 if (data == NULL)
504 goto out_close; 504 goto out_elf_end;
505 505
506 /* the start of this section is a zero-terminated string */ 506 /* the start of this section is a zero-terminated string */
507 strncpy(debuglink, data->d_buf, size); 507 strncpy(debuglink, data->d_buf, size);
508 508
509out_elf_end:
509 elf_end(elf); 510 elf_end(elf);
510
511out_close: 511out_close:
512 close(fd); 512 close(fd);
513out: 513out:
@@ -1018,6 +1018,601 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
1018 return err; 1018 return err;
1019} 1019}
1020 1020
1021static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
1022{
1023 ssize_t r;
1024 size_t n;
1025 int err = -1;
1026 char *buf = malloc(page_size);
1027
1028 if (buf == NULL)
1029 return -1;
1030
1031 if (lseek(to, to_offs, SEEK_SET) != to_offs)
1032 goto out;
1033
1034 if (lseek(from, from_offs, SEEK_SET) != from_offs)
1035 goto out;
1036
1037 while (len) {
1038 n = page_size;
1039 if (len < n)
1040 n = len;
1041 /* Use read because mmap won't work on proc files */
1042 r = read(from, buf, n);
1043 if (r < 0)
1044 goto out;
1045 if (!r)
1046 break;
1047 n = r;
1048 r = write(to, buf, n);
1049 if (r < 0)
1050 goto out;
1051 if ((size_t)r != n)
1052 goto out;
1053 len -= n;
1054 }
1055
1056 err = 0;
1057out:
1058 free(buf);
1059 return err;
1060}
1061
1062struct kcore {
1063 int fd;
1064 int elfclass;
1065 Elf *elf;
1066 GElf_Ehdr ehdr;
1067};
1068
1069static int kcore__open(struct kcore *kcore, const char *filename)
1070{
1071 GElf_Ehdr *ehdr;
1072
1073 kcore->fd = open(filename, O_RDONLY);
1074 if (kcore->fd == -1)
1075 return -1;
1076
1077 kcore->elf = elf_begin(kcore->fd, ELF_C_READ, NULL);
1078 if (!kcore->elf)
1079 goto out_close;
1080
1081 kcore->elfclass = gelf_getclass(kcore->elf);
1082 if (kcore->elfclass == ELFCLASSNONE)
1083 goto out_end;
1084
1085 ehdr = gelf_getehdr(kcore->elf, &kcore->ehdr);
1086 if (!ehdr)
1087 goto out_end;
1088
1089 return 0;
1090
1091out_end:
1092 elf_end(kcore->elf);
1093out_close:
1094 close(kcore->fd);
1095 return -1;
1096}
1097
1098static int kcore__init(struct kcore *kcore, char *filename, int elfclass,
1099 bool temp)
1100{
1101 GElf_Ehdr *ehdr;
1102
1103 kcore->elfclass = elfclass;
1104
1105 if (temp)
1106 kcore->fd = mkstemp(filename);
1107 else
1108 kcore->fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400);
1109 if (kcore->fd == -1)
1110 return -1;
1111
1112 kcore->elf = elf_begin(kcore->fd, ELF_C_WRITE, NULL);
1113 if (!kcore->elf)
1114 goto out_close;
1115
1116 if (!gelf_newehdr(kcore->elf, elfclass))
1117 goto out_end;
1118
1119 ehdr = gelf_getehdr(kcore->elf, &kcore->ehdr);
1120 if (!ehdr)
1121 goto out_end;
1122
1123 return 0;
1124
1125out_end:
1126 elf_end(kcore->elf);
1127out_close:
1128 close(kcore->fd);
1129 unlink(filename);
1130 return -1;
1131}
1132
1133static void kcore__close(struct kcore *kcore)
1134{
1135 elf_end(kcore->elf);
1136 close(kcore->fd);
1137}
1138
1139static int kcore__copy_hdr(struct kcore *from, struct kcore *to, size_t count)
1140{
1141 GElf_Ehdr *ehdr = &to->ehdr;
1142 GElf_Ehdr *kehdr = &from->ehdr;
1143
1144 memcpy(ehdr->e_ident, kehdr->e_ident, EI_NIDENT);
1145 ehdr->e_type = kehdr->e_type;
1146 ehdr->e_machine = kehdr->e_machine;
1147 ehdr->e_version = kehdr->e_version;
1148 ehdr->e_entry = 0;
1149 ehdr->e_shoff = 0;
1150 ehdr->e_flags = kehdr->e_flags;
1151 ehdr->e_phnum = count;
1152 ehdr->e_shentsize = 0;
1153 ehdr->e_shnum = 0;
1154 ehdr->e_shstrndx = 0;
1155
1156 if (from->elfclass == ELFCLASS32) {
1157 ehdr->e_phoff = sizeof(Elf32_Ehdr);
1158 ehdr->e_ehsize = sizeof(Elf32_Ehdr);
1159 ehdr->e_phentsize = sizeof(Elf32_Phdr);
1160 } else {
1161 ehdr->e_phoff = sizeof(Elf64_Ehdr);
1162 ehdr->e_ehsize = sizeof(Elf64_Ehdr);
1163 ehdr->e_phentsize = sizeof(Elf64_Phdr);
1164 }
1165
1166 if (!gelf_update_ehdr(to->elf, ehdr))
1167 return -1;
1168
1169 if (!gelf_newphdr(to->elf, count))
1170 return -1;
1171
1172 return 0;
1173}
1174
1175static int kcore__add_phdr(struct kcore *kcore, int idx, off_t offset,
1176 u64 addr, u64 len)
1177{
1178 GElf_Phdr gphdr;
1179 GElf_Phdr *phdr;
1180
1181 phdr = gelf_getphdr(kcore->elf, idx, &gphdr);
1182 if (!phdr)
1183 return -1;
1184
1185 phdr->p_type = PT_LOAD;
1186 phdr->p_flags = PF_R | PF_W | PF_X;
1187 phdr->p_offset = offset;
1188 phdr->p_vaddr = addr;
1189 phdr->p_paddr = 0;
1190 phdr->p_filesz = len;
1191 phdr->p_memsz = len;
1192 phdr->p_align = page_size;
1193
1194 if (!gelf_update_phdr(kcore->elf, idx, phdr))
1195 return -1;
1196
1197 return 0;
1198}
1199
1200static off_t kcore__write(struct kcore *kcore)
1201{
1202 return elf_update(kcore->elf, ELF_C_WRITE);
1203}
1204
1205struct phdr_data {
1206 off_t offset;
1207 u64 addr;
1208 u64 len;
1209};
1210
1211struct kcore_copy_info {
1212 u64 stext;
1213 u64 etext;
1214 u64 first_symbol;
1215 u64 last_symbol;
1216 u64 first_module;
1217 u64 last_module_symbol;
1218 struct phdr_data kernel_map;
1219 struct phdr_data modules_map;
1220};
1221
1222static int kcore_copy__process_kallsyms(void *arg, const char *name, char type,
1223 u64 start)
1224{
1225 struct kcore_copy_info *kci = arg;
1226
1227 if (!symbol_type__is_a(type, MAP__FUNCTION))
1228 return 0;
1229
1230 if (strchr(name, '[')) {
1231 if (start > kci->last_module_symbol)
1232 kci->last_module_symbol = start;
1233 return 0;
1234 }
1235
1236 if (!kci->first_symbol || start < kci->first_symbol)
1237 kci->first_symbol = start;
1238
1239 if (!kci->last_symbol || start > kci->last_symbol)
1240 kci->last_symbol = start;
1241
1242 if (!strcmp(name, "_stext")) {
1243 kci->stext = start;
1244 return 0;
1245 }
1246
1247 if (!strcmp(name, "_etext")) {
1248 kci->etext = start;
1249 return 0;
1250 }
1251
1252 return 0;
1253}
1254
1255static int kcore_copy__parse_kallsyms(struct kcore_copy_info *kci,
1256 const char *dir)
1257{
1258 char kallsyms_filename[PATH_MAX];
1259
1260 scnprintf(kallsyms_filename, PATH_MAX, "%s/kallsyms", dir);
1261
1262 if (symbol__restricted_filename(kallsyms_filename, "/proc/kallsyms"))
1263 return -1;
1264
1265 if (kallsyms__parse(kallsyms_filename, kci,
1266 kcore_copy__process_kallsyms) < 0)
1267 return -1;
1268
1269 return 0;
1270}
1271
1272static int kcore_copy__process_modules(void *arg,
1273 const char *name __maybe_unused,
1274 u64 start)
1275{
1276 struct kcore_copy_info *kci = arg;
1277
1278 if (!kci->first_module || start < kci->first_module)
1279 kci->first_module = start;
1280
1281 return 0;
1282}
1283
1284static int kcore_copy__parse_modules(struct kcore_copy_info *kci,
1285 const char *dir)
1286{
1287 char modules_filename[PATH_MAX];
1288
1289 scnprintf(modules_filename, PATH_MAX, "%s/modules", dir);
1290
1291 if (symbol__restricted_filename(modules_filename, "/proc/modules"))
1292 return -1;
1293
1294 if (modules__parse(modules_filename, kci,
1295 kcore_copy__process_modules) < 0)
1296 return -1;
1297
1298 return 0;
1299}
1300
1301static void kcore_copy__map(struct phdr_data *p, u64 start, u64 end, u64 pgoff,
1302 u64 s, u64 e)
1303{
1304 if (p->addr || s < start || s >= end)
1305 return;
1306
1307 p->addr = s;
1308 p->offset = (s - start) + pgoff;
1309 p->len = e < end ? e - s : end - s;
1310}
1311
1312static int kcore_copy__read_map(u64 start, u64 len, u64 pgoff, void *data)
1313{
1314 struct kcore_copy_info *kci = data;
1315 u64 end = start + len;
1316
1317 kcore_copy__map(&kci->kernel_map, start, end, pgoff, kci->stext,
1318 kci->etext);
1319
1320 kcore_copy__map(&kci->modules_map, start, end, pgoff, kci->first_module,
1321 kci->last_module_symbol);
1322
1323 return 0;
1324}
1325
1326static int kcore_copy__read_maps(struct kcore_copy_info *kci, Elf *elf)
1327{
1328 if (elf_read_maps(elf, true, kcore_copy__read_map, kci) < 0)
1329 return -1;
1330
1331 return 0;
1332}
1333
1334static int kcore_copy__calc_maps(struct kcore_copy_info *kci, const char *dir,
1335 Elf *elf)
1336{
1337 if (kcore_copy__parse_kallsyms(kci, dir))
1338 return -1;
1339
1340 if (kcore_copy__parse_modules(kci, dir))
1341 return -1;
1342
1343 if (kci->stext)
1344 kci->stext = round_down(kci->stext, page_size);
1345 else
1346 kci->stext = round_down(kci->first_symbol, page_size);
1347
1348 if (kci->etext) {
1349 kci->etext = round_up(kci->etext, page_size);
1350 } else if (kci->last_symbol) {
1351 kci->etext = round_up(kci->last_symbol, page_size);
1352 kci->etext += page_size;
1353 }
1354
1355 kci->first_module = round_down(kci->first_module, page_size);
1356
1357 if (kci->last_module_symbol) {
1358 kci->last_module_symbol = round_up(kci->last_module_symbol,
1359 page_size);
1360 kci->last_module_symbol += page_size;
1361 }
1362
1363 if (!kci->stext || !kci->etext)
1364 return -1;
1365
1366 if (kci->first_module && !kci->last_module_symbol)
1367 return -1;
1368
1369 return kcore_copy__read_maps(kci, elf);
1370}
1371
1372static int kcore_copy__copy_file(const char *from_dir, const char *to_dir,
1373 const char *name)
1374{
1375 char from_filename[PATH_MAX];
1376 char to_filename[PATH_MAX];
1377
1378 scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name);
1379 scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name);
1380
1381 return copyfile_mode(from_filename, to_filename, 0400);
1382}
1383
1384static int kcore_copy__unlink(const char *dir, const char *name)
1385{
1386 char filename[PATH_MAX];
1387
1388 scnprintf(filename, PATH_MAX, "%s/%s", dir, name);
1389
1390 return unlink(filename);
1391}
1392
1393static int kcore_copy__compare_fds(int from, int to)
1394{
1395 char *buf_from;
1396 char *buf_to;
1397 ssize_t ret;
1398 size_t len;
1399 int err = -1;
1400
1401 buf_from = malloc(page_size);
1402 buf_to = malloc(page_size);
1403 if (!buf_from || !buf_to)
1404 goto out;
1405
1406 while (1) {
1407 /* Use read because mmap won't work on proc files */
1408 ret = read(from, buf_from, page_size);
1409 if (ret < 0)
1410 goto out;
1411
1412 if (!ret)
1413 break;
1414
1415 len = ret;
1416
1417 if (readn(to, buf_to, len) != (int)len)
1418 goto out;
1419
1420 if (memcmp(buf_from, buf_to, len))
1421 goto out;
1422 }
1423
1424 err = 0;
1425out:
1426 free(buf_to);
1427 free(buf_from);
1428 return err;
1429}
1430
1431static int kcore_copy__compare_files(const char *from_filename,
1432 const char *to_filename)
1433{
1434 int from, to, err = -1;
1435
1436 from = open(from_filename, O_RDONLY);
1437 if (from < 0)
1438 return -1;
1439
1440 to = open(to_filename, O_RDONLY);
1441 if (to < 0)
1442 goto out_close_from;
1443
1444 err = kcore_copy__compare_fds(from, to);
1445
1446 close(to);
1447out_close_from:
1448 close(from);
1449 return err;
1450}
1451
1452static int kcore_copy__compare_file(const char *from_dir, const char *to_dir,
1453 const char *name)
1454{
1455 char from_filename[PATH_MAX];
1456 char to_filename[PATH_MAX];
1457
1458 scnprintf(from_filename, PATH_MAX, "%s/%s", from_dir, name);
1459 scnprintf(to_filename, PATH_MAX, "%s/%s", to_dir, name);
1460
1461 return kcore_copy__compare_files(from_filename, to_filename);
1462}
1463
1464/**
1465 * kcore_copy - copy kallsyms, modules and kcore from one directory to another.
1466 * @from_dir: from directory
1467 * @to_dir: to directory
1468 *
1469 * This function copies kallsyms, modules and kcore files from one directory to
1470 * another. kallsyms and modules are copied entirely. Only code segments are
1471 * copied from kcore. It is assumed that two segments suffice: one for the
1472 * kernel proper and one for all the modules. The code segments are determined
1473 * from kallsyms and modules files. The kernel map starts at _stext or the
1474 * lowest function symbol, and ends at _etext or the highest function symbol.
1475 * The module map starts at the lowest module address and ends at the highest
1476 * module symbol. Start addresses are rounded down to the nearest page. End
1477 * addresses are rounded up to the nearest page. An extra page is added to the
1478 * highest kernel symbol and highest module symbol to, hopefully, encompass that
1479 * symbol too. Because it contains only code sections, the resulting kcore is
1480 * unusual. One significant peculiarity is that the mapping (start -> pgoff)
1481 * is not the same for the kernel map and the modules map. That happens because
1482 * the data is copied adjacently whereas the original kcore has gaps. Finally,
1483 * kallsyms and modules files are compared with their copies to check that
1484 * modules have not been loaded or unloaded while the copies were taking place.
1485 *
1486 * Return: %0 on success, %-1 on failure.
1487 */
1488int kcore_copy(const char *from_dir, const char *to_dir)
1489{
1490 struct kcore kcore;
1491 struct kcore extract;
1492 size_t count = 2;
1493 int idx = 0, err = -1;
1494 off_t offset = page_size, sz, modules_offset = 0;
1495 struct kcore_copy_info kci = { .stext = 0, };
1496 char kcore_filename[PATH_MAX];
1497 char extract_filename[PATH_MAX];
1498
1499 if (kcore_copy__copy_file(from_dir, to_dir, "kallsyms"))
1500 return -1;
1501
1502 if (kcore_copy__copy_file(from_dir, to_dir, "modules"))
1503 goto out_unlink_kallsyms;
1504
1505 scnprintf(kcore_filename, PATH_MAX, "%s/kcore", from_dir);
1506 scnprintf(extract_filename, PATH_MAX, "%s/kcore", to_dir);
1507
1508 if (kcore__open(&kcore, kcore_filename))
1509 goto out_unlink_modules;
1510
1511 if (kcore_copy__calc_maps(&kci, from_dir, kcore.elf))
1512 goto out_kcore_close;
1513
1514 if (kcore__init(&extract, extract_filename, kcore.elfclass, false))
1515 goto out_kcore_close;
1516
1517 if (!kci.modules_map.addr)
1518 count -= 1;
1519
1520 if (kcore__copy_hdr(&kcore, &extract, count))
1521 goto out_extract_close;
1522
1523 if (kcore__add_phdr(&extract, idx++, offset, kci.kernel_map.addr,
1524 kci.kernel_map.len))
1525 goto out_extract_close;
1526
1527 if (kci.modules_map.addr) {
1528 modules_offset = offset + kci.kernel_map.len;
1529 if (kcore__add_phdr(&extract, idx, modules_offset,
1530 kci.modules_map.addr, kci.modules_map.len))
1531 goto out_extract_close;
1532 }
1533
1534 sz = kcore__write(&extract);
1535 if (sz < 0 || sz > offset)
1536 goto out_extract_close;
1537
1538 if (copy_bytes(kcore.fd, kci.kernel_map.offset, extract.fd, offset,
1539 kci.kernel_map.len))
1540 goto out_extract_close;
1541
1542 if (modules_offset && copy_bytes(kcore.fd, kci.modules_map.offset,
1543 extract.fd, modules_offset,
1544 kci.modules_map.len))
1545 goto out_extract_close;
1546
1547 if (kcore_copy__compare_file(from_dir, to_dir, "modules"))
1548 goto out_extract_close;
1549
1550 if (kcore_copy__compare_file(from_dir, to_dir, "kallsyms"))
1551 goto out_extract_close;
1552
1553 err = 0;
1554
1555out_extract_close:
1556 kcore__close(&extract);
1557 if (err)
1558 unlink(extract_filename);
1559out_kcore_close:
1560 kcore__close(&kcore);
1561out_unlink_modules:
1562 if (err)
1563 kcore_copy__unlink(to_dir, "modules");
1564out_unlink_kallsyms:
1565 if (err)
1566 kcore_copy__unlink(to_dir, "kallsyms");
1567
1568 return err;
1569}
1570
1571int kcore_extract__create(struct kcore_extract *kce)
1572{
1573 struct kcore kcore;
1574 struct kcore extract;
1575 size_t count = 1;
1576 int idx = 0, err = -1;
1577 off_t offset = page_size, sz;
1578
1579 if (kcore__open(&kcore, kce->kcore_filename))
1580 return -1;
1581
1582 strcpy(kce->extract_filename, PERF_KCORE_EXTRACT);
1583 if (kcore__init(&extract, kce->extract_filename, kcore.elfclass, true))
1584 goto out_kcore_close;
1585
1586 if (kcore__copy_hdr(&kcore, &extract, count))
1587 goto out_extract_close;
1588
1589 if (kcore__add_phdr(&extract, idx, offset, kce->addr, kce->len))
1590 goto out_extract_close;
1591
1592 sz = kcore__write(&extract);
1593 if (sz < 0 || sz > offset)
1594 goto out_extract_close;
1595
1596 if (copy_bytes(kcore.fd, kce->offs, extract.fd, offset, kce->len))
1597 goto out_extract_close;
1598
1599 err = 0;
1600
1601out_extract_close:
1602 kcore__close(&extract);
1603 if (err)
1604 unlink(kce->extract_filename);
1605out_kcore_close:
1606 kcore__close(&kcore);
1607
1608 return err;
1609}
1610
1611void kcore_extract__delete(struct kcore_extract *kce)
1612{
1613 unlink(kce->extract_filename);
1614}
1615
1021void symbol__elf_init(void) 1616void symbol__elf_init(void)
1022{ 1617{
1023 elf_version(EV_CURRENT); 1618 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index 3a802c300fc5..2d2dd0532b5a 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -308,6 +308,21 @@ int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused,
308 return -1; 308 return -1;
309} 309}
310 310
311int kcore_extract__create(struct kcore_extract *kce __maybe_unused)
312{
313 return -1;
314}
315
316void kcore_extract__delete(struct kcore_extract *kce __maybe_unused)
317{
318}
319
320int kcore_copy(const char *from_dir __maybe_unused,
321 const char *to_dir __maybe_unused)
322{
323 return -1;
324}
325
311void symbol__elf_init(void) 326void symbol__elf_init(void)
312{ 327{
313} 328}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 7eb0362f4ffd..c0c36965fff0 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -51,6 +51,7 @@ static enum dso_binary_type binary_type_symtab[] = {
51 DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 51 DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
52 DSO_BINARY_TYPE__GUEST_KMODULE, 52 DSO_BINARY_TYPE__GUEST_KMODULE,
53 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 53 DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
54 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
54 DSO_BINARY_TYPE__NOT_FOUND, 55 DSO_BINARY_TYPE__NOT_FOUND,
55}; 56};
56 57
@@ -159,10 +160,12 @@ again:
159 160
160 if (choose_best_symbol(curr, next) == SYMBOL_A) { 161 if (choose_best_symbol(curr, next) == SYMBOL_A) {
161 rb_erase(&next->rb_node, symbols); 162 rb_erase(&next->rb_node, symbols);
163 symbol__delete(next);
162 goto again; 164 goto again;
163 } else { 165 } else {
164 nd = rb_next(&curr->rb_node); 166 nd = rb_next(&curr->rb_node);
165 rb_erase(&curr->rb_node, symbols); 167 rb_erase(&curr->rb_node, symbols);
168 symbol__delete(curr);
166 } 169 }
167 } 170 }
168} 171}
@@ -499,6 +502,64 @@ out_failure:
499 return -1; 502 return -1;
500} 503}
501 504
505int modules__parse(const char *filename, void *arg,
506 int (*process_module)(void *arg, const char *name,
507 u64 start))
508{
509 char *line = NULL;
510 size_t n;
511 FILE *file;
512 int err = 0;
513
514 file = fopen(filename, "r");
515 if (file == NULL)
516 return -1;
517
518 while (1) {
519 char name[PATH_MAX];
520 u64 start;
521 char *sep;
522 ssize_t line_len;
523
524 line_len = getline(&line, &n, file);
525 if (line_len < 0) {
526 if (feof(file))
527 break;
528 err = -1;
529 goto out;
530 }
531
532 if (!line) {
533 err = -1;
534 goto out;
535 }
536
537 line[--line_len] = '\0'; /* \n */
538
539 sep = strrchr(line, 'x');
540 if (sep == NULL)
541 continue;
542
543 hex2u64(sep + 1, &start);
544
545 sep = strchr(line, ' ');
546 if (sep == NULL)
547 continue;
548
549 *sep = '\0';
550
551 scnprintf(name, sizeof(name), "[%s]", line);
552
553 err = process_module(arg, name, start);
554 if (err)
555 break;
556 }
557out:
558 free(line);
559 fclose(file);
560 return err;
561}
562
502struct process_kallsyms_args { 563struct process_kallsyms_args {
503 struct map *map; 564 struct map *map;
504 struct dso *dso; 565 struct dso *dso;
@@ -739,51 +800,242 @@ bool symbol__restricted_filename(const char *filename,
739 return restricted; 800 return restricted;
740} 801}
741 802
742struct kcore_mapfn_data { 803struct module_info {
743 struct dso *dso; 804 struct rb_node rb_node;
744 enum map_type type; 805 char *name;
745 struct list_head maps; 806 u64 start;
746}; 807};
747 808
748static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 809static void add_module(struct module_info *mi, struct rb_root *modules)
749{ 810{
750 struct kcore_mapfn_data *md = data; 811 struct rb_node **p = &modules->rb_node;
751 struct map *map; 812 struct rb_node *parent = NULL;
813 struct module_info *m;
752 814
753 map = map__new2(start, md->dso, md->type); 815 while (*p != NULL) {
754 if (map == NULL) 816 parent = *p;
817 m = rb_entry(parent, struct module_info, rb_node);
818 if (strcmp(mi->name, m->name) < 0)
819 p = &(*p)->rb_left;
820 else
821 p = &(*p)->rb_right;
822 }
823 rb_link_node(&mi->rb_node, parent, p);
824 rb_insert_color(&mi->rb_node, modules);
825}
826
827static void delete_modules(struct rb_root *modules)
828{
829 struct module_info *mi;
830 struct rb_node *next = rb_first(modules);
831
832 while (next) {
833 mi = rb_entry(next, struct module_info, rb_node);
834 next = rb_next(&mi->rb_node);
835 rb_erase(&mi->rb_node, modules);
836 free(mi->name);
837 free(mi);
838 }
839}
840
841static struct module_info *find_module(const char *name,
842 struct rb_root *modules)
843{
844 struct rb_node *n = modules->rb_node;
845
846 while (n) {
847 struct module_info *m;
848 int cmp;
849
850 m = rb_entry(n, struct module_info, rb_node);
851 cmp = strcmp(name, m->name);
852 if (cmp < 0)
853 n = n->rb_left;
854 else if (cmp > 0)
855 n = n->rb_right;
856 else
857 return m;
858 }
859
860 return NULL;
861}
862
863static int __read_proc_modules(void *arg, const char *name, u64 start)
864{
865 struct rb_root *modules = arg;
866 struct module_info *mi;
867
868 mi = zalloc(sizeof(struct module_info));
869 if (!mi)
755 return -ENOMEM; 870 return -ENOMEM;
756 871
757 map->end = map->start + len; 872 mi->name = strdup(name);
758 map->pgoff = pgoff; 873 mi->start = start;
759 874
760 list_add(&map->node, &md->maps); 875 if (!mi->name) {
876 free(mi);
877 return -ENOMEM;
878 }
879
880 add_module(mi, modules);
881
882 return 0;
883}
884
885static int read_proc_modules(const char *filename, struct rb_root *modules)
886{
887 if (symbol__restricted_filename(filename, "/proc/modules"))
888 return -1;
889
890 if (modules__parse(filename, modules, __read_proc_modules)) {
891 delete_modules(modules);
892 return -1;
893 }
761 894
762 return 0; 895 return 0;
763} 896}
764 897
898int compare_proc_modules(const char *from, const char *to)
899{
900 struct rb_root from_modules = RB_ROOT;
901 struct rb_root to_modules = RB_ROOT;
902 struct rb_node *from_node, *to_node;
903 struct module_info *from_m, *to_m;
904 int ret = -1;
905
906 if (read_proc_modules(from, &from_modules))
907 return -1;
908
909 if (read_proc_modules(to, &to_modules))
910 goto out_delete_from;
911
912 from_node = rb_first(&from_modules);
913 to_node = rb_first(&to_modules);
914 while (from_node) {
915 if (!to_node)
916 break;
917
918 from_m = rb_entry(from_node, struct module_info, rb_node);
919 to_m = rb_entry(to_node, struct module_info, rb_node);
920
921 if (from_m->start != to_m->start ||
922 strcmp(from_m->name, to_m->name))
923 break;
924
925 from_node = rb_next(from_node);
926 to_node = rb_next(to_node);
927 }
928
929 if (!from_node && !to_node)
930 ret = 0;
931
932 delete_modules(&to_modules);
933out_delete_from:
934 delete_modules(&from_modules);
935
936 return ret;
937}
938
939static int do_validate_kcore_modules(const char *filename, struct map *map,
940 struct map_groups *kmaps)
941{
942 struct rb_root modules = RB_ROOT;
943 struct map *old_map;
944 int err;
945
946 err = read_proc_modules(filename, &modules);
947 if (err)
948 return err;
949
950 old_map = map_groups__first(kmaps, map->type);
951 while (old_map) {
952 struct map *next = map_groups__next(old_map);
953 struct module_info *mi;
954
955 if (old_map == map || old_map->start == map->start) {
956 /* The kernel map */
957 old_map = next;
958 continue;
959 }
960
961 /* Module must be in memory at the same address */
962 mi = find_module(old_map->dso->short_name, &modules);
963 if (!mi || mi->start != old_map->start) {
964 err = -EINVAL;
965 goto out;
966 }
967
968 old_map = next;
969 }
970out:
971 delete_modules(&modules);
972 return err;
973}
974
765/* 975/*
766 * If kallsyms is referenced by name then we look for kcore in the same 976 * If kallsyms is referenced by name then we look for filename in the same
767 * directory. 977 * directory.
768 */ 978 */
769static bool kcore_filename_from_kallsyms_filename(char *kcore_filename, 979static bool filename_from_kallsyms_filename(char *filename,
770 const char *kallsyms_filename) 980 const char *base_name,
981 const char *kallsyms_filename)
771{ 982{
772 char *name; 983 char *name;
773 984
774 strcpy(kcore_filename, kallsyms_filename); 985 strcpy(filename, kallsyms_filename);
775 name = strrchr(kcore_filename, '/'); 986 name = strrchr(filename, '/');
776 if (!name) 987 if (!name)
777 return false; 988 return false;
778 989
779 if (!strcmp(name, "/kallsyms")) { 990 name += 1;
780 strcpy(name, "/kcore"); 991
992 if (!strcmp(name, "kallsyms")) {
993 strcpy(name, base_name);
781 return true; 994 return true;
782 } 995 }
783 996
784 return false; 997 return false;
785} 998}
786 999
1000static int validate_kcore_modules(const char *kallsyms_filename,
1001 struct map *map)
1002{
1003 struct map_groups *kmaps = map__kmap(map)->kmaps;
1004 char modules_filename[PATH_MAX];
1005
1006 if (!filename_from_kallsyms_filename(modules_filename, "modules",
1007 kallsyms_filename))
1008 return -EINVAL;
1009
1010 if (do_validate_kcore_modules(modules_filename, map, kmaps))
1011 return -EINVAL;
1012
1013 return 0;
1014}
1015
1016struct kcore_mapfn_data {
1017 struct dso *dso;
1018 enum map_type type;
1019 struct list_head maps;
1020};
1021
1022static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)
1023{
1024 struct kcore_mapfn_data *md = data;
1025 struct map *map;
1026
1027 map = map__new2(start, md->dso, md->type);
1028 if (map == NULL)
1029 return -ENOMEM;
1030
1031 map->end = map->start + len;
1032 map->pgoff = pgoff;
1033
1034 list_add(&map->node, &md->maps);
1035
1036 return 0;
1037}
1038
787static int dso__load_kcore(struct dso *dso, struct map *map, 1039static int dso__load_kcore(struct dso *dso, struct map *map,
788 const char *kallsyms_filename) 1040 const char *kallsyms_filename)
789{ 1041{
@@ -800,8 +1052,12 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
800 if (map != machine->vmlinux_maps[map->type]) 1052 if (map != machine->vmlinux_maps[map->type])
801 return -EINVAL; 1053 return -EINVAL;
802 1054
803 if (!kcore_filename_from_kallsyms_filename(kcore_filename, 1055 if (!filename_from_kallsyms_filename(kcore_filename, "kcore",
804 kallsyms_filename)) 1056 kallsyms_filename))
1057 return -EINVAL;
1058
1059 /* All modules must be present at their original addresses */
1060 if (validate_kcore_modules(kallsyms_filename, map))
805 return -EINVAL; 1061 return -EINVAL;
806 1062
807 md.dso = dso; 1063 md.dso = dso;
@@ -1188,6 +1444,105 @@ out:
1188 return err; 1444 return err;
1189} 1445}
1190 1446
1447static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
1448{
1449 char kallsyms_filename[PATH_MAX];
1450 struct dirent *dent;
1451 int ret = -1;
1452 DIR *d;
1453
1454 d = opendir(dir);
1455 if (!d)
1456 return -1;
1457
1458 while (1) {
1459 dent = readdir(d);
1460 if (!dent)
1461 break;
1462 if (dent->d_type != DT_DIR)
1463 continue;
1464 scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
1465 "%s/%s/kallsyms", dir, dent->d_name);
1466 if (!validate_kcore_modules(kallsyms_filename, map)) {
1467 strlcpy(dir, kallsyms_filename, dir_sz);
1468 ret = 0;
1469 break;
1470 }
1471 }
1472
1473 closedir(d);
1474
1475 return ret;
1476}
1477
1478static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1479{
1480 u8 host_build_id[BUILD_ID_SIZE];
1481 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1482 bool is_host = false;
1483 char path[PATH_MAX];
1484
1485 if (!dso->has_build_id) {
1486 /*
1487 * Last resort, if we don't have a build-id and couldn't find
1488 * any vmlinux file, try the running kernel kallsyms table.
1489 */
1490 goto proc_kallsyms;
1491 }
1492
1493 if (sysfs__read_build_id("/sys/kernel/notes", host_build_id,
1494 sizeof(host_build_id)) == 0)
1495 is_host = dso__build_id_equal(dso, host_build_id);
1496
1497 build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
1498
1499 /* Use /proc/kallsyms if possible */
1500 if (is_host) {
1501 DIR *d;
1502 int fd;
1503
1504 /* If no cached kcore go with /proc/kallsyms */
1505 scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s",
1506 buildid_dir, sbuild_id);
1507 d = opendir(path);
1508 if (!d)
1509 goto proc_kallsyms;
1510 closedir(d);
1511
1512 /*
1513 * Do not check the build-id cache, until we know we cannot use
1514 * /proc/kcore.
1515 */
1516 fd = open("/proc/kcore", O_RDONLY);
1517 if (fd != -1) {
1518 close(fd);
1519 /* If module maps match go with /proc/kallsyms */
1520 if (!validate_kcore_modules("/proc/kallsyms", map))
1521 goto proc_kallsyms;
1522 }
1523
1524 /* Find kallsyms in build-id cache with kcore */
1525 if (!find_matching_kcore(map, path, sizeof(path)))
1526 return strdup(path);
1527
1528 goto proc_kallsyms;
1529 }
1530
1531 scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s",
1532 buildid_dir, sbuild_id);
1533
1534 if (access(path, F_OK)) {
1535 pr_err("No kallsyms or vmlinux with build-id %s was found\n",
1536 sbuild_id);
1537 return NULL;
1538 }
1539
1540 return strdup(path);
1541
1542proc_kallsyms:
1543 return strdup("/proc/kallsyms");
1544}
1545
1191static int dso__load_kernel_sym(struct dso *dso, struct map *map, 1546static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1192 symbol_filter_t filter) 1547 symbol_filter_t filter)
1193{ 1548{
@@ -1214,7 +1569,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1214 goto do_kallsyms; 1569 goto do_kallsyms;
1215 } 1570 }
1216 1571
1217 if (symbol_conf.vmlinux_name != NULL) { 1572 if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) {
1218 err = dso__load_vmlinux(dso, map, 1573 err = dso__load_vmlinux(dso, map,
1219 symbol_conf.vmlinux_name, filter); 1574 symbol_conf.vmlinux_name, filter);
1220 if (err > 0) { 1575 if (err > 0) {
@@ -1226,7 +1581,7 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1226 return err; 1581 return err;
1227 } 1582 }
1228 1583
1229 if (vmlinux_path != NULL) { 1584 if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) {
1230 err = dso__load_vmlinux_path(dso, map, filter); 1585 err = dso__load_vmlinux_path(dso, map, filter);
1231 if (err > 0) 1586 if (err > 0)
1232 return err; 1587 return err;
@@ -1236,51 +1591,11 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map,
1236 if (symbol_conf.symfs[0] != 0) 1591 if (symbol_conf.symfs[0] != 0)
1237 return -1; 1592 return -1;
1238 1593
1239 /* 1594 kallsyms_allocated_filename = dso__find_kallsyms(dso, map);
1240 * Say the kernel DSO was created when processing the build-id header table, 1595 if (!kallsyms_allocated_filename)
1241 * we have a build-id, so check if it is the same as the running kernel, 1596 return -1;
1242 * using it if it is.
1243 */
1244 if (dso->has_build_id) {
1245 u8 kallsyms_build_id[BUILD_ID_SIZE];
1246 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1247
1248 if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
1249 sizeof(kallsyms_build_id)) == 0) {
1250 if (dso__build_id_equal(dso, kallsyms_build_id)) {
1251 kallsyms_filename = "/proc/kallsyms";
1252 goto do_kallsyms;
1253 }
1254 }
1255 /*
1256 * Now look if we have it on the build-id cache in
1257 * $HOME/.debug/[kernel.kallsyms].
1258 */
1259 build_id__sprintf(dso->build_id, sizeof(dso->build_id),
1260 sbuild_id);
1261
1262 if (asprintf(&kallsyms_allocated_filename,
1263 "%s/.debug/[kernel.kallsyms]/%s",
1264 getenv("HOME"), sbuild_id) == -1) {
1265 pr_err("Not enough memory for kallsyms file lookup\n");
1266 return -1;
1267 }
1268
1269 kallsyms_filename = kallsyms_allocated_filename;
1270 1597
1271 if (access(kallsyms_filename, F_OK)) { 1598 kallsyms_filename = kallsyms_allocated_filename;
1272 pr_err("No kallsyms or vmlinux with build-id %s "
1273 "was found\n", sbuild_id);
1274 free(kallsyms_allocated_filename);
1275 return -1;
1276 }
1277 } else {
1278 /*
1279 * Last resort, if we don't have a build-id and couldn't find
1280 * any vmlinux file, try the running kernel kallsyms table.
1281 */
1282 kallsyms_filename = "/proc/kallsyms";
1283 }
1284 1599
1285do_kallsyms: 1600do_kallsyms:
1286 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 1601 err = dso__load_kallsyms(dso, kallsyms_filename, map, filter);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index fd5b70ea2981..07de8fea2f48 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -13,7 +13,7 @@
13#include <libgen.h> 13#include <libgen.h>
14#include "build-id.h" 14#include "build-id.h"
15 15
16#ifdef LIBELF_SUPPORT 16#ifdef HAVE_LIBELF_SUPPORT
17#include <libelf.h> 17#include <libelf.h>
18#include <gelf.h> 18#include <gelf.h>
19#endif 19#endif
@@ -21,7 +21,7 @@
21 21
22#include "dso.h" 22#include "dso.h"
23 23
24#ifdef HAVE_CPLUS_DEMANGLE 24#ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
25extern char *cplus_demangle(const char *, int); 25extern char *cplus_demangle(const char *, int);
26 26
27static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i) 27static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i)
@@ -46,7 +46,7 @@ static inline char *bfd_demangle(void __maybe_unused *v,
46 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP; 46 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
47 * for newer versions we can use mmap to reduce memory usage: 47 * for newer versions we can use mmap to reduce memory usage:
48 */ 48 */
49#ifdef LIBELF_MMAP 49#ifdef HAVE_LIBELF_MMAP_SUPPORT
50# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP 50# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP
51#else 51#else
52# define PERF_ELF_C_READ_MMAP ELF_C_READ 52# define PERF_ELF_C_READ_MMAP ELF_C_READ
@@ -85,6 +85,7 @@ struct symbol_conf {
85 unsigned short priv_size; 85 unsigned short priv_size;
86 unsigned short nr_events; 86 unsigned short nr_events;
87 bool try_vmlinux_path, 87 bool try_vmlinux_path,
88 ignore_vmlinux,
88 show_kernel_path, 89 show_kernel_path,
89 use_modules, 90 use_modules,
90 sort_by_name, 91 sort_by_name,
@@ -178,7 +179,7 @@ struct symsrc {
178 int fd; 179 int fd;
179 enum dso_binary_type type; 180 enum dso_binary_type type;
180 181
181#ifdef LIBELF_SUPPORT 182#ifdef HAVE_LIBELF_SUPPORT
182 Elf *elf; 183 Elf *elf;
183 GElf_Ehdr ehdr; 184 GElf_Ehdr ehdr;
184 185
@@ -222,6 +223,9 @@ int sysfs__read_build_id(const char *filename, void *bf, size_t size);
222int kallsyms__parse(const char *filename, void *arg, 223int kallsyms__parse(const char *filename, void *arg,
223 int (*process_symbol)(void *arg, const char *name, 224 int (*process_symbol)(void *arg, const char *name,
224 char type, u64 start)); 225 char type, u64 start));
226int modules__parse(const char *filename, void *arg,
227 int (*process_module)(void *arg, const char *name,
228 u64 start));
225int filename__read_debuglink(const char *filename, char *debuglink, 229int filename__read_debuglink(const char *filename, char *debuglink,
226 size_t size); 230 size_t size);
227 231
@@ -252,4 +256,21 @@ typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
252int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data, 256int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
253 bool *is_64_bit); 257 bool *is_64_bit);
254 258
259#define PERF_KCORE_EXTRACT "/tmp/perf-kcore-XXXXXX"
260
261struct kcore_extract {
262 char *kcore_filename;
263 u64 addr;
264 u64 offs;
265 u64 len;
266 char extract_filename[sizeof(PERF_KCORE_EXTRACT)];
267 int fd;
268};
269
270int kcore_extract__create(struct kcore_extract *kce);
271void kcore_extract__delete(struct kcore_extract *kce);
272
273int kcore_copy(const char *from_dir, const char *to_dir);
274int compare_proc_modules(const char *from, const char *to);
275
255#endif /* __PERF_SYMBOL */ 276#endif /* __PERF_SYMBOL */
diff --git a/tools/perf/util/sysfs.c b/tools/perf/util/sysfs.c
deleted file mode 100644
index f71e9eafe15a..000000000000
--- a/tools/perf/util/sysfs.c
+++ /dev/null
@@ -1,60 +0,0 @@
1
2#include "util.h"
3#include "sysfs.h"
4
5static const char * const sysfs_known_mountpoints[] = {
6 "/sys",
7 0,
8};
9
10static int sysfs_found;
11char sysfs_mountpoint[PATH_MAX + 1];
12
13static int sysfs_valid_mountpoint(const char *sysfs)
14{
15 struct statfs st_fs;
16
17 if (statfs(sysfs, &st_fs) < 0)
18 return -ENOENT;
19 else if (st_fs.f_type != (long) SYSFS_MAGIC)
20 return -ENOENT;
21
22 return 0;
23}
24
25const char *sysfs_find_mountpoint(void)
26{
27 const char * const *ptr;
28 char type[100];
29 FILE *fp;
30
31 if (sysfs_found)
32 return (const char *) sysfs_mountpoint;
33
34 ptr = sysfs_known_mountpoints;
35 while (*ptr) {
36 if (sysfs_valid_mountpoint(*ptr) == 0) {
37 sysfs_found = 1;
38 strcpy(sysfs_mountpoint, *ptr);
39 return sysfs_mountpoint;
40 }
41 ptr++;
42 }
43
44 /* give up and parse /proc/mounts */
45 fp = fopen("/proc/mounts", "r");
46 if (fp == NULL)
47 return NULL;
48
49 while (!sysfs_found &&
50 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
51 sysfs_mountpoint, type) == 2) {
52
53 if (strcmp(type, "sysfs") == 0)
54 sysfs_found = 1;
55 }
56
57 fclose(fp);
58
59 return sysfs_found ? sysfs_mountpoint : NULL;
60}
diff --git a/tools/perf/util/sysfs.h b/tools/perf/util/sysfs.h
deleted file mode 100644
index a813b7203938..000000000000
--- a/tools/perf/util/sysfs.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef __SYSFS_H__
2#define __SYSFS_H__
3
4const char *sysfs_find_mountpoint(void);
5
6#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
index 065528b7563e..3c778a07b7cc 100644
--- a/tools/perf/util/target.c
+++ b/tools/perf/util/target.c
@@ -13,9 +13,9 @@
13#include <string.h> 13#include <string.h>
14 14
15 15
16enum perf_target_errno perf_target__validate(struct perf_target *target) 16enum target_errno target__validate(struct target *target)
17{ 17{
18 enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS; 18 enum target_errno ret = TARGET_ERRNO__SUCCESS;
19 19
20 if (target->pid) 20 if (target->pid)
21 target->tid = target->pid; 21 target->tid = target->pid;
@@ -23,42 +23,42 @@ enum perf_target_errno perf_target__validate(struct perf_target *target)
23 /* CPU and PID are mutually exclusive */ 23 /* CPU and PID are mutually exclusive */
24 if (target->tid && target->cpu_list) { 24 if (target->tid && target->cpu_list) {
25 target->cpu_list = NULL; 25 target->cpu_list = NULL;
26 if (ret == PERF_ERRNO_TARGET__SUCCESS) 26 if (ret == TARGET_ERRNO__SUCCESS)
27 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU; 27 ret = TARGET_ERRNO__PID_OVERRIDE_CPU;
28 } 28 }
29 29
30 /* UID and PID are mutually exclusive */ 30 /* UID and PID are mutually exclusive */
31 if (target->tid && target->uid_str) { 31 if (target->tid && target->uid_str) {
32 target->uid_str = NULL; 32 target->uid_str = NULL;
33 if (ret == PERF_ERRNO_TARGET__SUCCESS) 33 if (ret == TARGET_ERRNO__SUCCESS)
34 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID; 34 ret = TARGET_ERRNO__PID_OVERRIDE_UID;
35 } 35 }
36 36
37 /* UID and CPU are mutually exclusive */ 37 /* UID and CPU are mutually exclusive */
38 if (target->uid_str && target->cpu_list) { 38 if (target->uid_str && target->cpu_list) {
39 target->cpu_list = NULL; 39 target->cpu_list = NULL;
40 if (ret == PERF_ERRNO_TARGET__SUCCESS) 40 if (ret == TARGET_ERRNO__SUCCESS)
41 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU; 41 ret = TARGET_ERRNO__UID_OVERRIDE_CPU;
42 } 42 }
43 43
44 /* PID and SYSTEM are mutually exclusive */ 44 /* PID and SYSTEM are mutually exclusive */
45 if (target->tid && target->system_wide) { 45 if (target->tid && target->system_wide) {
46 target->system_wide = false; 46 target->system_wide = false;
47 if (ret == PERF_ERRNO_TARGET__SUCCESS) 47 if (ret == TARGET_ERRNO__SUCCESS)
48 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM; 48 ret = TARGET_ERRNO__PID_OVERRIDE_SYSTEM;
49 } 49 }
50 50
51 /* UID and SYSTEM are mutually exclusive */ 51 /* UID and SYSTEM are mutually exclusive */
52 if (target->uid_str && target->system_wide) { 52 if (target->uid_str && target->system_wide) {
53 target->system_wide = false; 53 target->system_wide = false;
54 if (ret == PERF_ERRNO_TARGET__SUCCESS) 54 if (ret == TARGET_ERRNO__SUCCESS)
55 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM; 55 ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM;
56 } 56 }
57 57
58 return ret; 58 return ret;
59} 59}
60 60
61enum perf_target_errno perf_target__parse_uid(struct perf_target *target) 61enum target_errno target__parse_uid(struct target *target)
62{ 62{
63 struct passwd pwd, *result; 63 struct passwd pwd, *result;
64 char buf[1024]; 64 char buf[1024];
@@ -66,7 +66,7 @@ enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
66 66
67 target->uid = UINT_MAX; 67 target->uid = UINT_MAX;
68 if (str == NULL) 68 if (str == NULL)
69 return PERF_ERRNO_TARGET__SUCCESS; 69 return TARGET_ERRNO__SUCCESS;
70 70
71 /* Try user name first */ 71 /* Try user name first */
72 getpwnam_r(str, &pwd, buf, sizeof(buf), &result); 72 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
@@ -79,22 +79,22 @@ enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
79 int uid = strtol(str, &endptr, 10); 79 int uid = strtol(str, &endptr, 10);
80 80
81 if (*endptr != '\0') 81 if (*endptr != '\0')
82 return PERF_ERRNO_TARGET__INVALID_UID; 82 return TARGET_ERRNO__INVALID_UID;
83 83
84 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result); 84 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
85 85
86 if (result == NULL) 86 if (result == NULL)
87 return PERF_ERRNO_TARGET__USER_NOT_FOUND; 87 return TARGET_ERRNO__USER_NOT_FOUND;
88 } 88 }
89 89
90 target->uid = result->pw_uid; 90 target->uid = result->pw_uid;
91 return PERF_ERRNO_TARGET__SUCCESS; 91 return TARGET_ERRNO__SUCCESS;
92} 92}
93 93
94/* 94/*
95 * This must have a same ordering as the enum perf_target_errno. 95 * This must have a same ordering as the enum target_errno.
96 */ 96 */
97static const char *perf_target__error_str[] = { 97static const char *target__error_str[] = {
98 "PID/TID switch overriding CPU", 98 "PID/TID switch overriding CPU",
99 "PID/TID switch overriding UID", 99 "PID/TID switch overriding UID",
100 "UID switch overriding CPU", 100 "UID switch overriding CPU",
@@ -104,7 +104,7 @@ static const char *perf_target__error_str[] = {
104 "Problems obtaining information for user %s", 104 "Problems obtaining information for user %s",
105}; 105};
106 106
107int perf_target__strerror(struct perf_target *target, int errnum, 107int target__strerror(struct target *target, int errnum,
108 char *buf, size_t buflen) 108 char *buf, size_t buflen)
109{ 109{
110 int idx; 110 int idx;
@@ -124,21 +124,19 @@ int perf_target__strerror(struct perf_target *target, int errnum,
124 return 0; 124 return 0;
125 } 125 }
126 126
127 if (errnum < __PERF_ERRNO_TARGET__START || 127 if (errnum < __TARGET_ERRNO__START || errnum >= __TARGET_ERRNO__END)
128 errnum >= __PERF_ERRNO_TARGET__END)
129 return -1; 128 return -1;
130 129
131 idx = errnum - __PERF_ERRNO_TARGET__START; 130 idx = errnum - __TARGET_ERRNO__START;
132 msg = perf_target__error_str[idx]; 131 msg = target__error_str[idx];
133 132
134 switch (errnum) { 133 switch (errnum) {
135 case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU 134 case TARGET_ERRNO__PID_OVERRIDE_CPU ... TARGET_ERRNO__UID_OVERRIDE_SYSTEM:
136 ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
137 snprintf(buf, buflen, "%s", msg); 135 snprintf(buf, buflen, "%s", msg);
138 break; 136 break;
139 137
140 case PERF_ERRNO_TARGET__INVALID_UID: 138 case TARGET_ERRNO__INVALID_UID:
141 case PERF_ERRNO_TARGET__USER_NOT_FOUND: 139 case TARGET_ERRNO__USER_NOT_FOUND:
142 snprintf(buf, buflen, msg, target->uid_str); 140 snprintf(buf, buflen, msg, target->uid_str);
143 break; 141 break;
144 142
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
index a4be8575fda5..2d0c50690892 100644
--- a/tools/perf/util/target.h
+++ b/tools/perf/util/target.h
@@ -4,7 +4,7 @@
4#include <stdbool.h> 4#include <stdbool.h>
5#include <sys/types.h> 5#include <sys/types.h>
6 6
7struct perf_target { 7struct target {
8 const char *pid; 8 const char *pid;
9 const char *tid; 9 const char *tid;
10 const char *cpu_list; 10 const char *cpu_list;
@@ -12,10 +12,11 @@ struct perf_target {
12 uid_t uid; 12 uid_t uid;
13 bool system_wide; 13 bool system_wide;
14 bool uses_mmap; 14 bool uses_mmap;
15 bool force_per_cpu;
15}; 16};
16 17
17enum perf_target_errno { 18enum target_errno {
18 PERF_ERRNO_TARGET__SUCCESS = 0, 19 TARGET_ERRNO__SUCCESS = 0,
19 20
20 /* 21 /*
21 * Choose an arbitrary negative big number not to clash with standard 22 * Choose an arbitrary negative big number not to clash with standard
@@ -24,42 +25,40 @@ enum perf_target_errno {
24 * 25 *
25 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html 26 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
26 */ 27 */
27 __PERF_ERRNO_TARGET__START = -10000, 28 __TARGET_ERRNO__START = -10000,
28 29
30 /* for target__validate() */
31 TARGET_ERRNO__PID_OVERRIDE_CPU = __TARGET_ERRNO__START,
32 TARGET_ERRNO__PID_OVERRIDE_UID,
33 TARGET_ERRNO__UID_OVERRIDE_CPU,
34 TARGET_ERRNO__PID_OVERRIDE_SYSTEM,
35 TARGET_ERRNO__UID_OVERRIDE_SYSTEM,
29 36
30 /* for perf_target__validate() */ 37 /* for target__parse_uid() */
31 PERF_ERRNO_TARGET__PID_OVERRIDE_CPU = __PERF_ERRNO_TARGET__START, 38 TARGET_ERRNO__INVALID_UID,
32 PERF_ERRNO_TARGET__PID_OVERRIDE_UID, 39 TARGET_ERRNO__USER_NOT_FOUND,
33 PERF_ERRNO_TARGET__UID_OVERRIDE_CPU,
34 PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM,
35 PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM,
36 40
37 /* for perf_target__parse_uid() */ 41 __TARGET_ERRNO__END,
38 PERF_ERRNO_TARGET__INVALID_UID,
39 PERF_ERRNO_TARGET__USER_NOT_FOUND,
40
41 __PERF_ERRNO_TARGET__END,
42}; 42};
43 43
44enum perf_target_errno perf_target__validate(struct perf_target *target); 44enum target_errno target__validate(struct target *target);
45enum perf_target_errno perf_target__parse_uid(struct perf_target *target); 45enum target_errno target__parse_uid(struct target *target);
46 46
47int perf_target__strerror(struct perf_target *target, int errnum, char *buf, 47int target__strerror(struct target *target, int errnum, char *buf, size_t buflen);
48 size_t buflen);
49 48
50static inline bool perf_target__has_task(struct perf_target *target) 49static inline bool target__has_task(struct target *target)
51{ 50{
52 return target->tid || target->pid || target->uid_str; 51 return target->tid || target->pid || target->uid_str;
53} 52}
54 53
55static inline bool perf_target__has_cpu(struct perf_target *target) 54static inline bool target__has_cpu(struct target *target)
56{ 55{
57 return target->system_wide || target->cpu_list; 56 return target->system_wide || target->cpu_list;
58} 57}
59 58
60static inline bool perf_target__none(struct perf_target *target) 59static inline bool target__none(struct target *target)
61{ 60{
62 return !perf_target__has_task(target) && !perf_target__has_cpu(target); 61 return !target__has_task(target) && !target__has_cpu(target);
63} 62}
64 63
65#endif /* _PERF_TARGET_H */ 64#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index e3d4a550a703..cd8e2f592719 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -6,86 +6,137 @@
6#include "thread.h" 6#include "thread.h"
7#include "util.h" 7#include "util.h"
8#include "debug.h" 8#include "debug.h"
9#include "comm.h"
9 10
10struct thread *thread__new(pid_t pid, pid_t tid) 11struct thread *thread__new(pid_t pid, pid_t tid)
11{ 12{
12 struct thread *self = zalloc(sizeof(*self)); 13 char *comm_str;
13 14 struct comm *comm;
14 if (self != NULL) { 15 struct thread *thread = zalloc(sizeof(*thread));
15 map_groups__init(&self->mg); 16
16 self->pid_ = pid; 17 if (thread != NULL) {
17 self->tid = tid; 18 map_groups__init(&thread->mg);
18 self->ppid = -1; 19 thread->pid_ = pid;
19 self->comm = malloc(32); 20 thread->tid = tid;
20 if (self->comm) 21 thread->ppid = -1;
21 snprintf(self->comm, 32, ":%d", self->tid); 22 INIT_LIST_HEAD(&thread->comm_list);
23
24 comm_str = malloc(32);
25 if (!comm_str)
26 goto err_thread;
27
28 snprintf(comm_str, 32, ":%d", tid);
29 comm = comm__new(comm_str, 0);
30 free(comm_str);
31 if (!comm)
32 goto err_thread;
33
34 list_add(&comm->list, &thread->comm_list);
35 }
36
37 return thread;
38
39err_thread:
40 free(thread);
41 return NULL;
42}
43
44void thread__delete(struct thread *thread)
45{
46 struct comm *comm, *tmp;
47
48 map_groups__exit(&thread->mg);
49 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
50 list_del(&comm->list);
51 comm__free(comm);
22 } 52 }
23 53
24 return self; 54 free(thread);
25} 55}
26 56
27void thread__delete(struct thread *self) 57struct comm *thread__comm(const struct thread *thread)
28{ 58{
29 map_groups__exit(&self->mg); 59 if (list_empty(&thread->comm_list))
30 free(self->comm); 60 return NULL;
31 free(self); 61
62 return list_first_entry(&thread->comm_list, struct comm, list);
32} 63}
33 64
34int thread__set_comm(struct thread *self, const char *comm) 65/* CHECKME: time should always be 0 if event aren't ordered */
66int thread__set_comm(struct thread *thread, const char *str, u64 timestamp)
35{ 67{
36 int err; 68 struct comm *new, *curr = thread__comm(thread);
37 69
38 if (self->comm) 70 /* Override latest entry if it had no specific time coverage */
39 free(self->comm); 71 if (!curr->start) {
40 self->comm = strdup(comm); 72 comm__override(curr, str, timestamp);
41 err = self->comm == NULL ? -ENOMEM : 0; 73 return 0;
42 if (!err) {
43 self->comm_set = true;
44 } 74 }
45 return err; 75
76 new = comm__new(str, timestamp);
77 if (!new)
78 return -ENOMEM;
79
80 list_add(&new->list, &thread->comm_list);
81 thread->comm_set = true;
82
83 return 0;
84}
85
86const char *thread__comm_str(const struct thread *thread)
87{
88 const struct comm *comm = thread__comm(thread);
89
90 if (!comm)
91 return NULL;
92
93 return comm__str(comm);
46} 94}
47 95
48int thread__comm_len(struct thread *self) 96/* CHECKME: it should probably better return the max comm len from its comm list */
97int thread__comm_len(struct thread *thread)
49{ 98{
50 if (!self->comm_len) { 99 if (!thread->comm_len) {
51 if (!self->comm) 100 const char *comm = thread__comm_str(thread);
101 if (!comm)
52 return 0; 102 return 0;
53 self->comm_len = strlen(self->comm); 103 thread->comm_len = strlen(comm);
54 } 104 }
55 105
56 return self->comm_len; 106 return thread->comm_len;
57} 107}
58 108
59size_t thread__fprintf(struct thread *thread, FILE *fp) 109size_t thread__fprintf(struct thread *thread, FILE *fp)
60{ 110{
61 return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) + 111 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
62 map_groups__fprintf(&thread->mg, verbose, fp); 112 map_groups__fprintf(&thread->mg, verbose, fp);
63} 113}
64 114
65void thread__insert_map(struct thread *self, struct map *map) 115void thread__insert_map(struct thread *thread, struct map *map)
66{ 116{
67 map_groups__fixup_overlappings(&self->mg, map, verbose, stderr); 117 map_groups__fixup_overlappings(&thread->mg, map, verbose, stderr);
68 map_groups__insert(&self->mg, map); 118 map_groups__insert(&thread->mg, map);
69} 119}
70 120
71int thread__fork(struct thread *self, struct thread *parent) 121int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
72{ 122{
73 int i; 123 int i, err;
74 124
75 if (parent->comm_set) { 125 if (parent->comm_set) {
76 if (self->comm) 126 const char *comm = thread__comm_str(parent);
77 free(self->comm); 127 if (!comm)
78 self->comm = strdup(parent->comm);
79 if (!self->comm)
80 return -ENOMEM; 128 return -ENOMEM;
81 self->comm_set = true; 129 err = thread__set_comm(thread, comm, timestamp);
130 if (!err)
131 return err;
132 thread->comm_set = true;
82 } 133 }
83 134
84 for (i = 0; i < MAP__NR_TYPES; ++i) 135 for (i = 0; i < MAP__NR_TYPES; ++i)
85 if (map_groups__clone(&self->mg, &parent->mg, i) < 0) 136 if (map_groups__clone(&thread->mg, &parent->mg, i) < 0)
86 return -ENOMEM; 137 return -ENOMEM;
87 138
88 self->ppid = parent->tid; 139 thread->ppid = parent->tid;
89 140
90 return 0; 141 return 0;
91} 142}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 4ebbb40d46d4..897c1b2a750a 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -2,6 +2,7 @@
2#define __PERF_THREAD_H 2#define __PERF_THREAD_H
3 3
4#include <linux/rbtree.h> 4#include <linux/rbtree.h>
5#include <linux/list.h>
5#include <unistd.h> 6#include <unistd.h>
6#include <sys/types.h> 7#include <sys/types.h>
7#include "symbol.h" 8#include "symbol.h"
@@ -18,31 +19,34 @@ struct thread {
18 char shortname[3]; 19 char shortname[3];
19 bool comm_set; 20 bool comm_set;
20 bool dead; /* if set thread has exited */ 21 bool dead; /* if set thread has exited */
21 char *comm; 22 struct list_head comm_list;
22 int comm_len; 23 int comm_len;
23 24
24 void *priv; 25 void *priv;
25}; 26};
26 27
27struct machine; 28struct machine;
29struct comm;
28 30
29struct thread *thread__new(pid_t pid, pid_t tid); 31struct thread *thread__new(pid_t pid, pid_t tid);
30void thread__delete(struct thread *self); 32void thread__delete(struct thread *thread);
31static inline void thread__exited(struct thread *thread) 33static inline void thread__exited(struct thread *thread)
32{ 34{
33 thread->dead = true; 35 thread->dead = true;
34} 36}
35 37
36int thread__set_comm(struct thread *self, const char *comm); 38int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp);
37int thread__comm_len(struct thread *self); 39int thread__comm_len(struct thread *thread);
38void thread__insert_map(struct thread *self, struct map *map); 40struct comm *thread__comm(const struct thread *thread);
39int thread__fork(struct thread *self, struct thread *parent); 41const char *thread__comm_str(const struct thread *thread);
42void thread__insert_map(struct thread *thread, struct map *map);
43int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
40size_t thread__fprintf(struct thread *thread, FILE *fp); 44size_t thread__fprintf(struct thread *thread, FILE *fp);
41 45
42static inline struct map *thread__find_map(struct thread *self, 46static inline struct map *thread__find_map(struct thread *thread,
43 enum map_type type, u64 addr) 47 enum map_type type, u64 addr)
44{ 48{
45 return self ? map_groups__find(&self->mg, type, addr) : NULL; 49 return thread ? map_groups__find(&thread->mg, type, addr) : NULL;
46} 50}
47 51
48void thread__find_addr_map(struct thread *thread, struct machine *machine, 52void thread__find_addr_map(struct thread *thread, struct machine *machine,
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index f857b51b6bde..ce793c7dd23c 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -27,7 +27,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
27 float ksamples_per_sec; 27 float ksamples_per_sec;
28 float esamples_percent; 28 float esamples_percent;
29 struct perf_record_opts *opts = &top->record_opts; 29 struct perf_record_opts *opts = &top->record_opts;
30 struct perf_target *target = &opts->target; 30 struct target *target = &opts->target;
31 size_t ret = 0; 31 size_t ret = 0;
32 32
33 if (top->samples) { 33 if (top->samples) {
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index b554ffc462b6..88cfeaff600b 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -24,6 +24,7 @@ struct perf_top {
24 u64 exact_samples; 24 u64 exact_samples;
25 u64 guest_us_samples, guest_kernel_samples; 25 u64 guest_us_samples, guest_kernel_samples;
26 int print_entries, count_filter, delay_secs; 26 int print_entries, count_filter, delay_secs;
27 int max_stack;
27 bool hide_kernel_symbols, hide_user_symbols, zero; 28 bool hide_kernel_symbols, hide_user_symbols, zero;
28 bool use_tui, use_stdio; 29 bool use_tui, use_stdio;
29 bool kptr_restrict_warned; 30 bool kptr_restrict_warned;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index e9e1c03f927d..6681f71f2f95 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -120,42 +120,6 @@ raw_field_value(struct event_format *event, const char *name, void *data)
120 return val; 120 return val;
121} 121}
122 122
123void *raw_field_ptr(struct event_format *event, const char *name, void *data)
124{
125 struct format_field *field;
126
127 field = pevent_find_any_field(event, name);
128 if (!field)
129 return NULL;
130
131 if (field->flags & FIELD_IS_DYNAMIC) {
132 int offset;
133
134 offset = *(int *)(data + field->offset);
135 offset &= 0xffff;
136
137 return data + offset;
138 }
139
140 return data + field->offset;
141}
142
143int trace_parse_common_type(struct pevent *pevent, void *data)
144{
145 struct pevent_record record;
146
147 record.data = data;
148 return pevent_data_type(pevent, &record);
149}
150
151int trace_parse_common_pid(struct pevent *pevent, void *data)
152{
153 struct pevent_record record;
154
155 record.data = data;
156 return pevent_data_pid(pevent, &record);
157}
158
159unsigned long long read_size(struct event_format *event, void *ptr, int size) 123unsigned long long read_size(struct event_format *event, void *ptr, int size)
160{ 124{
161 return pevent_read_number(event->pevent, ptr, size); 125 return pevent_read_number(event->pevent, ptr, size);
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index fafe1a40444a..04df63114109 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -11,8 +11,6 @@ union perf_event;
11struct perf_tool; 11struct perf_tool;
12struct thread; 12struct thread;
13 13
14extern struct pevent *perf_pevent;
15
16int bigendian(void); 14int bigendian(void);
17 15
18struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 16struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
@@ -23,26 +21,19 @@ int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
23int parse_event_file(struct pevent *pevent, 21int parse_event_file(struct pevent *pevent,
24 char *buf, unsigned long size, char *sys); 22 char *buf, unsigned long size, char *sys);
25 23
26struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu);
27
28unsigned long long 24unsigned long long
29raw_field_value(struct event_format *event, const char *name, void *data); 25raw_field_value(struct event_format *event, const char *name, void *data);
30void *raw_field_ptr(struct event_format *event, const char *name, void *data);
31 26
32void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); 27void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
33void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); 28void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
34 29
35ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); 30ssize_t trace_report(int fd, struct pevent **pevent, bool repipe);
36 31
37int trace_parse_common_type(struct pevent *pevent, void *data);
38int trace_parse_common_pid(struct pevent *pevent, void *data);
39
40struct event_format *trace_find_next_event(struct pevent *pevent, 32struct event_format *trace_find_next_event(struct pevent *pevent,
41 struct event_format *event); 33 struct event_format *event);
42unsigned long long read_size(struct event_format *event, void *ptr, int size); 34unsigned long long read_size(struct event_format *event, void *ptr, int size);
43unsigned long long eval_flag(const char *flag); 35unsigned long long eval_flag(const char *flag);
44 36
45struct pevent_record *trace_read_data(struct pevent *pevent, int cpu);
46int read_tracing_data(int fd, struct list_head *pattrs); 37int read_tracing_data(int fd, struct list_head *pattrs);
47 38
48struct tracing_data { 39struct tracing_data {
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
index 2f891f7e70bf..0efd5393de85 100644
--- a/tools/perf/util/unwind.c
+++ b/tools/perf/util/unwind.c
@@ -39,6 +39,15 @@ UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
39 39
40#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) 40#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
41 41
42extern int
43UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
44 unw_word_t ip,
45 unw_word_t segbase,
46 const char *obj_name, unw_word_t start,
47 unw_word_t end);
48
49#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
50
42#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ 51#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */
43#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ 52#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */
44 53
@@ -245,8 +254,9 @@ static int unwind_spec_ehframe(struct dso *dso, struct machine *machine,
245 return 0; 254 return 0;
246} 255}
247 256
248static int read_unwind_spec(struct dso *dso, struct machine *machine, 257static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
249 u64 *table_data, u64 *segbase, u64 *fde_count) 258 u64 *table_data, u64 *segbase,
259 u64 *fde_count)
250{ 260{
251 int ret = -EINVAL, fd; 261 int ret = -EINVAL, fd;
252 u64 offset; 262 u64 offset;
@@ -255,6 +265,7 @@ static int read_unwind_spec(struct dso *dso, struct machine *machine,
255 if (fd < 0) 265 if (fd < 0)
256 return -EINVAL; 266 return -EINVAL;
257 267
268 /* Check the .eh_frame section for unwinding info */
258 offset = elf_section_offset(fd, ".eh_frame_hdr"); 269 offset = elf_section_offset(fd, ".eh_frame_hdr");
259 close(fd); 270 close(fd);
260 271
@@ -263,10 +274,29 @@ static int read_unwind_spec(struct dso *dso, struct machine *machine,
263 table_data, segbase, 274 table_data, segbase,
264 fde_count); 275 fde_count);
265 276
266 /* TODO .debug_frame check if eh_frame_hdr fails */
267 return ret; 277 return ret;
268} 278}
269 279
280#ifndef NO_LIBUNWIND_DEBUG_FRAME
281static int read_unwind_spec_debug_frame(struct dso *dso,
282 struct machine *machine, u64 *offset)
283{
284 int fd = dso__data_fd(dso, machine);
285
286 if (fd < 0)
287 return -EINVAL;
288
289 /* Check the .debug_frame section for unwinding info */
290 *offset = elf_section_offset(fd, ".debug_frame");
291 close(fd);
292
293 if (*offset)
294 return 0;
295
296 return -EINVAL;
297}
298#endif
299
270static struct map *find_map(unw_word_t ip, struct unwind_info *ui) 300static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
271{ 301{
272 struct addr_location al; 302 struct addr_location al;
@@ -291,20 +321,33 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
291 321
292 pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); 322 pr_debug("unwind: find_proc_info dso %s\n", map->dso->name);
293 323
294 if (read_unwind_spec(map->dso, ui->machine, 324 /* Check the .eh_frame section for unwinding info */
295 &table_data, &segbase, &fde_count)) 325 if (!read_unwind_spec_eh_frame(map->dso, ui->machine,
296 return -EINVAL; 326 &table_data, &segbase, &fde_count)) {
327 memset(&di, 0, sizeof(di));
328 di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
329 di.start_ip = map->start;
330 di.end_ip = map->end;
331 di.u.rti.segbase = map->start + segbase;
332 di.u.rti.table_data = map->start + table_data;
333 di.u.rti.table_len = fde_count * sizeof(struct table_entry)
334 / sizeof(unw_word_t);
335 return dwarf_search_unwind_table(as, ip, &di, pi,
336 need_unwind_info, arg);
337 }
338
339#ifndef NO_LIBUNWIND_DEBUG_FRAME
340 /* Check the .debug_frame section for unwinding info */
341 if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
342 memset(&di, 0, sizeof(di));
343 dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
344 map->start, map->end);
345 return dwarf_search_unwind_table(as, ip, &di, pi,
346 need_unwind_info, arg);
347 }
348#endif
297 349
298 memset(&di, 0, sizeof(di)); 350 return -EINVAL;
299 di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
300 di.start_ip = map->start;
301 di.end_ip = map->end;
302 di.u.rti.segbase = map->start + segbase;
303 di.u.rti.table_data = map->start + table_data;
304 di.u.rti.table_len = fde_count * sizeof(struct table_entry)
305 / sizeof(unw_word_t);
306 return dwarf_search_unwind_table(as, ip, &di, pi,
307 need_unwind_info, arg);
308} 351}
309 352
310static int access_fpreg(unw_addr_space_t __maybe_unused as, 353static int access_fpreg(unw_addr_space_t __maybe_unused as,
@@ -516,7 +559,7 @@ static unw_accessors_t accessors = {
516}; 559};
517 560
518static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 561static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
519 void *arg) 562 void *arg, int max_stack)
520{ 563{
521 unw_addr_space_t addr_space; 564 unw_addr_space_t addr_space;
522 unw_cursor_t c; 565 unw_cursor_t c;
@@ -532,7 +575,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
532 if (ret) 575 if (ret)
533 display_error(ret); 576 display_error(ret);
534 577
535 while (!ret && (unw_step(&c) > 0)) { 578 while (!ret && (unw_step(&c) > 0) && max_stack--) {
536 unw_word_t ip; 579 unw_word_t ip;
537 580
538 unw_get_reg(&c, UNW_REG_IP, &ip); 581 unw_get_reg(&c, UNW_REG_IP, &ip);
@@ -545,7 +588,8 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
545 588
546int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 589int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
547 struct machine *machine, struct thread *thread, 590 struct machine *machine, struct thread *thread,
548 u64 sample_uregs, struct perf_sample *data) 591 u64 sample_uregs, struct perf_sample *data,
592 int max_stack)
549{ 593{
550 unw_word_t ip; 594 unw_word_t ip;
551 struct unwind_info ui = { 595 struct unwind_info ui = {
@@ -567,5 +611,5 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
567 if (ret) 611 if (ret)
568 return -ENOMEM; 612 return -ENOMEM;
569 613
570 return get_entries(&ui, cb, arg); 614 return get_entries(&ui, cb, arg, max_stack);
571} 615}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index cb6bc503a792..d5966f49e22c 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -13,12 +13,12 @@ struct unwind_entry {
13 13
14typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); 14typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
15 15
16#ifdef LIBUNWIND_SUPPORT 16#ifdef HAVE_LIBUNWIND_SUPPORT
17int unwind__get_entries(unwind_entry_cb_t cb, void *arg, 17int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
18 struct machine *machine, 18 struct machine *machine,
19 struct thread *thread, 19 struct thread *thread,
20 u64 sample_uregs, 20 u64 sample_uregs,
21 struct perf_sample *data); 21 struct perf_sample *data, int max_stack);
22int unwind__arch_reg_id(int regnum); 22int unwind__arch_reg_id(int regnum);
23#else 23#else
24static inline int 24static inline int
@@ -27,9 +27,10 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
27 struct machine *machine __maybe_unused, 27 struct machine *machine __maybe_unused,
28 struct thread *thread __maybe_unused, 28 struct thread *thread __maybe_unused,
29 u64 sample_uregs __maybe_unused, 29 u64 sample_uregs __maybe_unused,
30 struct perf_sample *data __maybe_unused) 30 struct perf_sample *data __maybe_unused,
31 int max_stack __maybe_unused)
31{ 32{
32 return 0; 33 return 0;
33} 34}
34#endif /* LIBUNWIND_SUPPORT */ 35#endif /* HAVE_LIBUNWIND_SUPPORT */
35#endif /* __UNWIND_H */ 36#endif /* __UNWIND_H */
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 6d17b18e915d..28a0a89c1f73 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,7 +1,7 @@
1#include "../perf.h" 1#include "../perf.h"
2#include "util.h" 2#include "util.h"
3#include <sys/mman.h> 3#include <sys/mman.h>
4#ifdef BACKTRACE_SUPPORT 4#ifdef HAVE_BACKTRACE_SUPPORT
5#include <execinfo.h> 5#include <execinfo.h>
6#endif 6#endif
7#include <stdio.h> 7#include <stdio.h>
@@ -55,17 +55,20 @@ int mkdir_p(char *path, mode_t mode)
55 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; 55 return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
56} 56}
57 57
58static int slow_copyfile(const char *from, const char *to) 58static int slow_copyfile(const char *from, const char *to, mode_t mode)
59{ 59{
60 int err = 0; 60 int err = -1;
61 char *line = NULL; 61 char *line = NULL;
62 size_t n; 62 size_t n;
63 FILE *from_fp = fopen(from, "r"), *to_fp; 63 FILE *from_fp = fopen(from, "r"), *to_fp;
64 mode_t old_umask;
64 65
65 if (from_fp == NULL) 66 if (from_fp == NULL)
66 goto out; 67 goto out;
67 68
69 old_umask = umask(mode ^ 0777);
68 to_fp = fopen(to, "w"); 70 to_fp = fopen(to, "w");
71 umask(old_umask);
69 if (to_fp == NULL) 72 if (to_fp == NULL)
70 goto out_fclose_from; 73 goto out_fclose_from;
71 74
@@ -82,7 +85,7 @@ out:
82 return err; 85 return err;
83} 86}
84 87
85int copyfile(const char *from, const char *to) 88int copyfile_mode(const char *from, const char *to, mode_t mode)
86{ 89{
87 int fromfd, tofd; 90 int fromfd, tofd;
88 struct stat st; 91 struct stat st;
@@ -93,13 +96,13 @@ int copyfile(const char *from, const char *to)
93 goto out; 96 goto out;
94 97
95 if (st.st_size == 0) /* /proc? do it slowly... */ 98 if (st.st_size == 0) /* /proc? do it slowly... */
96 return slow_copyfile(from, to); 99 return slow_copyfile(from, to, mode);
97 100
98 fromfd = open(from, O_RDONLY); 101 fromfd = open(from, O_RDONLY);
99 if (fromfd < 0) 102 if (fromfd < 0)
100 goto out; 103 goto out;
101 104
102 tofd = creat(to, 0755); 105 tofd = creat(to, mode);
103 if (tofd < 0) 106 if (tofd < 0)
104 goto out_close_from; 107 goto out_close_from;
105 108
@@ -121,6 +124,11 @@ out:
121 return err; 124 return err;
122} 125}
123 126
127int copyfile(const char *from, const char *to)
128{
129 return copyfile_mode(from, to, 0755);
130}
131
124unsigned long convert_unit(unsigned long value, char *unit) 132unsigned long convert_unit(unsigned long value, char *unit)
125{ 133{
126 *unit = ' '; 134 *unit = ' ';
@@ -204,7 +212,7 @@ int hex2u64(const char *ptr, u64 *long_val)
204} 212}
205 213
206/* Obtain a backtrace and print it to stdout. */ 214/* Obtain a backtrace and print it to stdout. */
207#ifdef BACKTRACE_SUPPORT 215#ifdef HAVE_BACKTRACE_SUPPORT
208void dump_stack(void) 216void dump_stack(void)
209{ 217{
210 void *array[16]; 218 void *array[16];
@@ -361,3 +369,47 @@ int parse_nsec_time(const char *str, u64 *ptime)
361 *ptime = time_sec * NSEC_PER_SEC + time_nsec; 369 *ptime = time_sec * NSEC_PER_SEC + time_nsec;
362 return 0; 370 return 0;
363} 371}
372
373unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
374{
375 struct parse_tag *i = tags;
376
377 while (i->tag) {
378 char *s;
379
380 s = strchr(str, i->tag);
381 if (s) {
382 unsigned long int value;
383 char *endptr;
384
385 value = strtoul(str, &endptr, 10);
386 if (s != endptr)
387 break;
388
389 if (value > ULONG_MAX / i->mult)
390 break;
391 value *= i->mult;
392 return value;
393 }
394 i++;
395 }
396
397 return (unsigned long) -1;
398}
399
400int filename__read_int(const char *filename, int *value)
401{
402 char line[64];
403 int fd = open(filename, O_RDONLY), err = -1;
404
405 if (fd < 0)
406 return -1;
407
408 if (read(fd, line, sizeof(line)) > 0) {
409 *value = atoi(line);
410 err = 0;
411 }
412
413 close(fd);
414 return err;
415}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index a53535949043..c8f362daba87 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -128,6 +128,8 @@ void put_tracing_file(char *file);
128#endif 128#endif
129#endif 129#endif
130 130
131#define PERF_GTK_DSO "libperf-gtk.so"
132
131/* General helper functions */ 133/* General helper functions */
132extern void usage(const char *err) NORETURN; 134extern void usage(const char *err) NORETURN;
133extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); 135extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
@@ -241,6 +243,7 @@ static inline int sane_case(int x, int high)
241 243
242int mkdir_p(char *path, mode_t mode); 244int mkdir_p(char *path, mode_t mode);
243int copyfile(const char *from, const char *to); 245int copyfile(const char *from, const char *to);
246int copyfile_mode(const char *from, const char *to, mode_t mode);
244 247
245s64 perf_atoll(const char *str); 248s64 perf_atoll(const char *str);
246char **argv_split(const char *str, int *argcp); 249char **argv_split(const char *str, int *argcp);
@@ -270,6 +273,13 @@ bool is_power_of_2(unsigned long n)
270 return (n != 0 && ((n & (n - 1)) == 0)); 273 return (n != 0 && ((n & (n - 1)) == 0));
271} 274}
272 275
276static inline unsigned next_pow2(unsigned x)
277{
278 if (!x)
279 return 1;
280 return 1ULL << (32 - __builtin_clz(x - 1));
281}
282
273size_t hex_width(u64 v); 283size_t hex_width(u64 v);
274int hex2u64(const char *ptr, u64 *val); 284int hex2u64(const char *ptr, u64 *val);
275 285
@@ -281,4 +291,20 @@ void dump_stack(void);
281extern unsigned int page_size; 291extern unsigned int page_size;
282 292
283void get_term_dimensions(struct winsize *ws); 293void get_term_dimensions(struct winsize *ws);
294
295struct parse_tag {
296 char tag;
297 int mult;
298};
299
300unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
301
302#define SRCLINE_UNKNOWN ((char *) "??:0")
303
304struct dso;
305
306char *get_srcline(struct dso *dso, unsigned long addr);
307void free_srcline(char *srcline);
308
309int filename__read_int(const char *filename, int *value);
284#endif /* GIT_COMPAT_UTIL_H */ 310#endif /* GIT_COMPAT_UTIL_H */