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