]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
fd20e811 | 2 | #include <inttypes.h> |
25da4fab ACM |
3 | #include <stdio.h> |
4 | #include <stdbool.h> | |
5 | #include <traceevent/event-parse.h> | |
6 | #include "evsel.h" | |
7 | #include "callchain.h" | |
8 | #include "map.h" | |
8ec20b17 | 9 | #include "strlist.h" |
25da4fab | 10 | #include "symbol.h" |
325fbff5 | 11 | #include "srcline.h" |
25da4fab ACM |
12 | |
13 | static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) | |
14 | { | |
15 | va_list args; | |
16 | int ret = 0; | |
17 | ||
18 | if (!*first) { | |
19 | ret += fprintf(fp, ","); | |
20 | } else { | |
21 | ret += fprintf(fp, ":"); | |
22 | *first = false; | |
23 | } | |
24 | ||
25 | va_start(args, fmt); | |
26 | ret += vfprintf(fp, fmt, args); | |
27 | va_end(args); | |
28 | return ret; | |
29 | } | |
30 | ||
31 | static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv) | |
32 | { | |
33 | return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val); | |
34 | } | |
35 | ||
36 | int perf_evsel__fprintf(struct perf_evsel *evsel, | |
37 | struct perf_attr_details *details, FILE *fp) | |
38 | { | |
39 | bool first = true; | |
40 | int printed = 0; | |
41 | ||
42 | if (details->event_group) { | |
43 | struct perf_evsel *pos; | |
44 | ||
45 | if (!perf_evsel__is_group_leader(evsel)) | |
46 | return 0; | |
47 | ||
48 | if (evsel->nr_members > 1) | |
49 | printed += fprintf(fp, "%s{", evsel->group_name ?: ""); | |
50 | ||
51 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | |
52 | for_each_group_member(pos, evsel) | |
53 | printed += fprintf(fp, ",%s", perf_evsel__name(pos)); | |
54 | ||
55 | if (evsel->nr_members > 1) | |
56 | printed += fprintf(fp, "}"); | |
57 | goto out; | |
58 | } | |
59 | ||
60 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | |
61 | ||
62 | if (details->verbose) { | |
63 | printed += perf_event_attr__fprintf(fp, &evsel->attr, | |
64 | __print_attr__fprintf, &first); | |
65 | } else if (details->freq) { | |
66 | const char *term = "sample_freq"; | |
67 | ||
68 | if (!evsel->attr.freq) | |
69 | term = "sample_period"; | |
70 | ||
71 | printed += comma_fprintf(fp, &first, " %s=%" PRIu64, | |
72 | term, (u64)evsel->attr.sample_freq); | |
73 | } | |
74 | ||
75 | if (details->trace_fields) { | |
76 | struct format_field *field; | |
77 | ||
78 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { | |
79 | printed += comma_fprintf(fp, &first, " (not a tracepoint)"); | |
80 | goto out; | |
81 | } | |
82 | ||
83 | field = evsel->tp_format->format.fields; | |
84 | if (field == NULL) { | |
85 | printed += comma_fprintf(fp, &first, " (no trace field)"); | |
86 | goto out; | |
87 | } | |
88 | ||
89 | printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name); | |
90 | ||
91 | field = field->next; | |
92 | while (field) { | |
93 | printed += comma_fprintf(fp, &first, "%s", field->name); | |
94 | field = field->next; | |
95 | } | |
96 | } | |
97 | out: | |
98 | fputc('\n', fp); | |
99 | return ++printed; | |
100 | } | |
101 | ||
102 | int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, | |
103 | unsigned int print_opts, struct callchain_cursor *cursor, | |
104 | FILE *fp) | |
105 | { | |
106 | int printed = 0; | |
107 | struct callchain_cursor_node *node; | |
108 | int print_ip = print_opts & EVSEL__PRINT_IP; | |
109 | int print_sym = print_opts & EVSEL__PRINT_SYM; | |
110 | int print_dso = print_opts & EVSEL__PRINT_DSO; | |
111 | int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; | |
112 | int print_oneline = print_opts & EVSEL__PRINT_ONELINE; | |
113 | int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; | |
114 | int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; | |
69b7e480 | 115 | int print_arrow = print_opts & EVSEL__PRINT_CALLCHAIN_ARROW; |
2d9bbf6e | 116 | int print_skip_ignored = print_opts & EVSEL__PRINT_SKIP_IGNORED; |
25da4fab | 117 | char s = print_oneline ? ' ' : '\t'; |
69b7e480 | 118 | bool first = true; |
25da4fab ACM |
119 | |
120 | if (sample->callchain) { | |
121 | struct addr_location node_al; | |
122 | ||
123 | callchain_cursor_commit(cursor); | |
124 | ||
125 | while (1) { | |
126 | u64 addr = 0; | |
127 | ||
128 | node = callchain_cursor_current(cursor); | |
129 | if (!node) | |
130 | break; | |
131 | ||
2d9bbf6e NK |
132 | if (node->sym && node->sym->ignore && print_skip_ignored) |
133 | goto next; | |
134 | ||
25da4fab ACM |
135 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); |
136 | ||
69b7e480 NK |
137 | if (print_arrow && !first) |
138 | printed += fprintf(fp, " <-"); | |
139 | ||
25da4fab ACM |
140 | if (print_ip) |
141 | printed += fprintf(fp, "%c%16" PRIx64, s, node->ip); | |
142 | ||
143 | if (node->map) | |
144 | addr = node->map->map_ip(node->map, node->ip); | |
145 | ||
146 | if (print_sym) { | |
147 | printed += fprintf(fp, " "); | |
148 | node_al.addr = addr; | |
149 | node_al.map = node->map; | |
150 | ||
151 | if (print_symoffset) { | |
152 | printed += __symbol__fprintf_symname_offs(node->sym, &node_al, | |
a8763445 NK |
153 | print_unknown_as_addr, |
154 | true, fp); | |
25da4fab ACM |
155 | } else { |
156 | printed += __symbol__fprintf_symname(node->sym, &node_al, | |
157 | print_unknown_as_addr, fp); | |
158 | } | |
159 | } | |
160 | ||
161 | if (print_dso) { | |
162 | printed += fprintf(fp, " ("); | |
163 | printed += map__fprintf_dsoname(node->map, fp); | |
164 | printed += fprintf(fp, ")"); | |
165 | } | |
166 | ||
167 | if (print_srcline) | |
168 | printed += map__fprintf_srcline(node->map, addr, "\n ", fp); | |
169 | ||
170 | if (!print_oneline) | |
171 | printed += fprintf(fp, "\n"); | |
e7a06a53 | 172 | |
325fbff5 NK |
173 | if (symbol_conf.inline_name && node->map) { |
174 | struct inline_node *inode; | |
175 | ||
176 | addr = map__rip_2objdump(node->map, node->ip), | |
177 | inode = dso__parse_addr_inlines(node->map->dso, addr); | |
178 | ||
179 | if (inode) { | |
180 | struct inline_list *ilist; | |
181 | ||
182 | list_for_each_entry(ilist, &inode->val, list) { | |
183 | if (print_arrow) | |
184 | printed += fprintf(fp, " <-"); | |
185 | ||
186 | /* IP is same, just skip it */ | |
187 | if (print_ip) | |
188 | printed += fprintf(fp, "%c%16s", | |
189 | s, ""); | |
190 | if (print_sym) | |
191 | printed += fprintf(fp, " %s", | |
192 | ilist->funcname); | |
193 | if (print_srcline) | |
194 | printed += fprintf(fp, "\n %s:%d", | |
195 | ilist->filename, | |
196 | ilist->line_nr); | |
197 | if (!print_oneline) | |
198 | printed += fprintf(fp, "\n"); | |
199 | } | |
200 | ||
201 | inline_node__delete(inode); | |
202 | } | |
203 | } | |
204 | ||
64eff7d9 DA |
205 | if (symbol_conf.bt_stop_list && |
206 | node->sym && | |
64eff7d9 DA |
207 | strlist__has_entry(symbol_conf.bt_stop_list, |
208 | node->sym->name)) { | |
209 | break; | |
210 | } | |
211 | ||
69b7e480 | 212 | first = false; |
2d9bbf6e NK |
213 | next: |
214 | callchain_cursor_advance(cursor); | |
25da4fab ACM |
215 | } |
216 | } | |
217 | ||
218 | return printed; | |
219 | } | |
220 | ||
221 | int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, | |
222 | int left_alignment, unsigned int print_opts, | |
223 | struct callchain_cursor *cursor, FILE *fp) | |
224 | { | |
225 | int printed = 0; | |
226 | int print_ip = print_opts & EVSEL__PRINT_IP; | |
227 | int print_sym = print_opts & EVSEL__PRINT_SYM; | |
228 | int print_dso = print_opts & EVSEL__PRINT_DSO; | |
229 | int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; | |
230 | int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; | |
231 | int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; | |
232 | ||
233 | if (cursor != NULL) { | |
234 | printed += sample__fprintf_callchain(sample, left_alignment, | |
235 | print_opts, cursor, fp); | |
e7a06a53 | 236 | } else { |
25da4fab ACM |
237 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); |
238 | ||
239 | if (print_ip) | |
240 | printed += fprintf(fp, "%16" PRIx64, sample->ip); | |
241 | ||
242 | if (print_sym) { | |
243 | printed += fprintf(fp, " "); | |
244 | if (print_symoffset) { | |
245 | printed += __symbol__fprintf_symname_offs(al->sym, al, | |
a8763445 NK |
246 | print_unknown_as_addr, |
247 | true, fp); | |
25da4fab ACM |
248 | } else { |
249 | printed += __symbol__fprintf_symname(al->sym, al, | |
250 | print_unknown_as_addr, fp); | |
251 | } | |
252 | } | |
253 | ||
254 | if (print_dso) { | |
255 | printed += fprintf(fp, " ("); | |
256 | printed += map__fprintf_dsoname(al->map, fp); | |
257 | printed += fprintf(fp, ")"); | |
258 | } | |
259 | ||
260 | if (print_srcline) | |
261 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); | |
262 | } | |
263 | ||
264 | return printed; | |
265 | } |