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