1 // SPDX-License-Identifier: GPL-2.0 2 #include <inttypes.h> 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" 9 #include "strlist.h" 10 #include "symbol.h" 11 #include "srcline.h" 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 tep_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; 115 int print_arrow = print_opts & EVSEL__PRINT_CALLCHAIN_ARROW; 116 int print_skip_ignored = print_opts & EVSEL__PRINT_SKIP_IGNORED; 117 char s = print_oneline ? ' ' : '\t'; 118 bool first = true; 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 132 if (node->sym && node->sym->ignore && print_skip_ignored) 133 goto next; 134 135 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); 136 137 if (print_arrow && !first) 138 printed += fprintf(fp, " <-"); 139 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, 153 print_unknown_as_addr, 154 true, fp); 155 } else { 156 printed += __symbol__fprintf_symname(node->sym, &node_al, 157 print_unknown_as_addr, fp); 158 } 159 } 160 161 if (print_dso && (!node->sym || !node->sym->inlined)) { 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 (node->sym && node->sym->inlined) 171 printed += fprintf(fp, " (inlined)"); 172 173 if (!print_oneline) 174 printed += fprintf(fp, "\n"); 175 176 if (symbol_conf.bt_stop_list && 177 node->sym && 178 strlist__has_entry(symbol_conf.bt_stop_list, 179 node->sym->name)) { 180 break; 181 } 182 183 first = false; 184 next: 185 callchain_cursor_advance(cursor); 186 } 187 } 188 189 return printed; 190 } 191 192 int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, 193 int left_alignment, unsigned int print_opts, 194 struct callchain_cursor *cursor, FILE *fp) 195 { 196 int printed = 0; 197 int print_ip = print_opts & EVSEL__PRINT_IP; 198 int print_sym = print_opts & EVSEL__PRINT_SYM; 199 int print_dso = print_opts & EVSEL__PRINT_DSO; 200 int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; 201 int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; 202 int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; 203 204 if (cursor != NULL) { 205 printed += sample__fprintf_callchain(sample, left_alignment, 206 print_opts, cursor, fp); 207 } else { 208 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); 209 210 if (print_ip) 211 printed += fprintf(fp, "%16" PRIx64, sample->ip); 212 213 if (print_sym) { 214 printed += fprintf(fp, " "); 215 if (print_symoffset) { 216 printed += __symbol__fprintf_symname_offs(al->sym, al, 217 print_unknown_as_addr, 218 true, fp); 219 } else { 220 printed += __symbol__fprintf_symname(al->sym, al, 221 print_unknown_as_addr, fp); 222 } 223 } 224 225 if (print_dso) { 226 printed += fprintf(fp, " ("); 227 printed += map__fprintf_dsoname(al->map, fp); 228 printed += fprintf(fp, ")"); 229 } 230 231 if (print_srcline) 232 printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); 233 } 234 235 return printed; 236 } 237