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