162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <inttypes.h>
362306a36Sopenharmony_ci#include <stdio.h>
462306a36Sopenharmony_ci#include <stdbool.h>
562306a36Sopenharmony_ci#include "util/evlist.h"
662306a36Sopenharmony_ci#include "evsel.h"
762306a36Sopenharmony_ci#include "util/evsel_fprintf.h"
862306a36Sopenharmony_ci#include "util/event.h"
962306a36Sopenharmony_ci#include "callchain.h"
1062306a36Sopenharmony_ci#include "map.h"
1162306a36Sopenharmony_ci#include "strlist.h"
1262306a36Sopenharmony_ci#include "symbol.h"
1362306a36Sopenharmony_ci#include "srcline.h"
1462306a36Sopenharmony_ci#include "dso.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
1762306a36Sopenharmony_ci#include <traceevent/event-parse.h>
1862306a36Sopenharmony_ci#endif
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	va_list args;
2362306a36Sopenharmony_ci	int ret = 0;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if (!*first) {
2662306a36Sopenharmony_ci		ret += fprintf(fp, ",");
2762306a36Sopenharmony_ci	} else {
2862306a36Sopenharmony_ci		ret += fprintf(fp, ":");
2962306a36Sopenharmony_ci		*first = false;
3062306a36Sopenharmony_ci	}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	va_start(args, fmt);
3362306a36Sopenharmony_ci	ret += vfprintf(fp, fmt, args);
3462306a36Sopenharmony_ci	va_end(args);
3562306a36Sopenharmony_ci	return ret;
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val);
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ciint evsel__fprintf(struct evsel *evsel, struct perf_attr_details *details, FILE *fp)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	bool first = true;
4662306a36Sopenharmony_ci	int printed = 0;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	if (details->event_group) {
4962306a36Sopenharmony_ci		struct evsel *pos;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		if (!evsel__is_group_leader(evsel))
5262306a36Sopenharmony_ci			return 0;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		if (evsel->core.nr_members > 1)
5562306a36Sopenharmony_ci			printed += fprintf(fp, "%s{", evsel->group_name ?: "");
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		printed += fprintf(fp, "%s", evsel__name(evsel));
5862306a36Sopenharmony_ci		for_each_group_member(pos, evsel)
5962306a36Sopenharmony_ci			printed += fprintf(fp, ",%s", evsel__name(pos));
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		if (evsel->core.nr_members > 1)
6262306a36Sopenharmony_ci			printed += fprintf(fp, "}");
6362306a36Sopenharmony_ci		goto out;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	printed += fprintf(fp, "%s", evsel__name(evsel));
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (details->verbose) {
6962306a36Sopenharmony_ci		printed += perf_event_attr__fprintf(fp, &evsel->core.attr,
7062306a36Sopenharmony_ci						    __print_attr__fprintf, &first);
7162306a36Sopenharmony_ci	} else if (details->freq) {
7262306a36Sopenharmony_ci		const char *term = "sample_freq";
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci		if (!evsel->core.attr.freq)
7562306a36Sopenharmony_ci			term = "sample_period";
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci		printed += comma_fprintf(fp, &first, " %s=%" PRIu64,
7862306a36Sopenharmony_ci					 term, (u64)evsel->core.attr.sample_freq);
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
8262306a36Sopenharmony_ci	if (details->trace_fields) {
8362306a36Sopenharmony_ci		struct tep_format_field *field;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) {
8662306a36Sopenharmony_ci			printed += comma_fprintf(fp, &first, " (not a tracepoint)");
8762306a36Sopenharmony_ci			goto out;
8862306a36Sopenharmony_ci		}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		field = evsel->tp_format->format.fields;
9162306a36Sopenharmony_ci		if (field == NULL) {
9262306a36Sopenharmony_ci			printed += comma_fprintf(fp, &first, " (no trace field)");
9362306a36Sopenharmony_ci			goto out;
9462306a36Sopenharmony_ci		}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci		printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci		field = field->next;
9962306a36Sopenharmony_ci		while (field) {
10062306a36Sopenharmony_ci			printed += comma_fprintf(fp, &first, "%s", field->name);
10162306a36Sopenharmony_ci			field = field->next;
10262306a36Sopenharmony_ci		}
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci#endif
10562306a36Sopenharmony_ciout:
10662306a36Sopenharmony_ci	fputc('\n', fp);
10762306a36Sopenharmony_ci	return ++printed;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#ifndef PYTHON_PERF
11162306a36Sopenharmony_ciint sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
11262306a36Sopenharmony_ci			      unsigned int print_opts, struct callchain_cursor *cursor,
11362306a36Sopenharmony_ci			      struct strlist *bt_stop_list, FILE *fp)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	int printed = 0;
11662306a36Sopenharmony_ci	struct callchain_cursor_node *node;
11762306a36Sopenharmony_ci	int print_ip = print_opts & EVSEL__PRINT_IP;
11862306a36Sopenharmony_ci	int print_sym = print_opts & EVSEL__PRINT_SYM;
11962306a36Sopenharmony_ci	int print_dso = print_opts & EVSEL__PRINT_DSO;
12062306a36Sopenharmony_ci	int print_dsoff = print_opts & EVSEL__PRINT_DSOFF;
12162306a36Sopenharmony_ci	int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
12262306a36Sopenharmony_ci	int print_oneline = print_opts & EVSEL__PRINT_ONELINE;
12362306a36Sopenharmony_ci	int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
12462306a36Sopenharmony_ci	int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
12562306a36Sopenharmony_ci	int print_arrow = print_opts & EVSEL__PRINT_CALLCHAIN_ARROW;
12662306a36Sopenharmony_ci	int print_skip_ignored = print_opts & EVSEL__PRINT_SKIP_IGNORED;
12762306a36Sopenharmony_ci	char s = print_oneline ? ' ' : '\t';
12862306a36Sopenharmony_ci	bool first = true;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (cursor == NULL)
13162306a36Sopenharmony_ci		return fprintf(fp, "<not enough memory for the callchain cursor>%s", print_oneline ? "" : "\n");
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (sample->callchain) {
13462306a36Sopenharmony_ci		callchain_cursor_commit(cursor);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		while (1) {
13762306a36Sopenharmony_ci			struct symbol *sym;
13862306a36Sopenharmony_ci			struct map *map;
13962306a36Sopenharmony_ci			u64 addr = 0;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci			node = callchain_cursor_current(cursor);
14262306a36Sopenharmony_ci			if (!node)
14362306a36Sopenharmony_ci				break;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci			sym = node->ms.sym;
14662306a36Sopenharmony_ci			map = node->ms.map;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci			if (sym && sym->ignore && print_skip_ignored)
14962306a36Sopenharmony_ci				goto next;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci			printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci			if (print_arrow && !first)
15462306a36Sopenharmony_ci				printed += fprintf(fp, " <-");
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci			if (map)
15762306a36Sopenharmony_ci				addr = map__map_ip(map, node->ip);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci			if (print_ip)
16062306a36Sopenharmony_ci				printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci			if (print_sym) {
16362306a36Sopenharmony_ci				struct addr_location node_al;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci				addr_location__init(&node_al);
16662306a36Sopenharmony_ci				printed += fprintf(fp, " ");
16762306a36Sopenharmony_ci				node_al.addr = addr;
16862306a36Sopenharmony_ci				node_al.map  = map__get(map);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci				if (print_symoffset) {
17162306a36Sopenharmony_ci					printed += __symbol__fprintf_symname_offs(sym, &node_al,
17262306a36Sopenharmony_ci										  print_unknown_as_addr,
17362306a36Sopenharmony_ci										  true, fp);
17462306a36Sopenharmony_ci				} else {
17562306a36Sopenharmony_ci					printed += __symbol__fprintf_symname(sym, &node_al,
17662306a36Sopenharmony_ci									     print_unknown_as_addr, fp);
17762306a36Sopenharmony_ci				}
17862306a36Sopenharmony_ci				addr_location__exit(&node_al);
17962306a36Sopenharmony_ci			}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci			if (print_dso && (!sym || !sym->inlined))
18262306a36Sopenharmony_ci				printed += map__fprintf_dsoname_dsoff(map, print_dsoff, addr, fp);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci			if (print_srcline)
18562306a36Sopenharmony_ci				printed += map__fprintf_srcline(map, addr, "\n  ", fp);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci			if (sym && sym->inlined)
18862306a36Sopenharmony_ci				printed += fprintf(fp, " (inlined)");
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci			if (!print_oneline)
19162306a36Sopenharmony_ci				printed += fprintf(fp, "\n");
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci			/* Add srccode here too? */
19462306a36Sopenharmony_ci			if (bt_stop_list && sym &&
19562306a36Sopenharmony_ci			    strlist__has_entry(bt_stop_list, sym->name)) {
19662306a36Sopenharmony_ci				break;
19762306a36Sopenharmony_ci			}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci			first = false;
20062306a36Sopenharmony_cinext:
20162306a36Sopenharmony_ci			callchain_cursor_advance(cursor);
20262306a36Sopenharmony_ci		}
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return printed;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ciint sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,
20962306a36Sopenharmony_ci			int left_alignment, unsigned int print_opts,
21062306a36Sopenharmony_ci			struct callchain_cursor *cursor, struct strlist *bt_stop_list, FILE *fp)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	int printed = 0;
21362306a36Sopenharmony_ci	int print_ip = print_opts & EVSEL__PRINT_IP;
21462306a36Sopenharmony_ci	int print_sym = print_opts & EVSEL__PRINT_SYM;
21562306a36Sopenharmony_ci	int print_dso = print_opts & EVSEL__PRINT_DSO;
21662306a36Sopenharmony_ci	int print_dsoff = print_opts & EVSEL__PRINT_DSOFF;
21762306a36Sopenharmony_ci	int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
21862306a36Sopenharmony_ci	int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
21962306a36Sopenharmony_ci	int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (cursor != NULL) {
22262306a36Sopenharmony_ci		printed += sample__fprintf_callchain(sample, left_alignment, print_opts,
22362306a36Sopenharmony_ci						     cursor, bt_stop_list, fp);
22462306a36Sopenharmony_ci	} else {
22562306a36Sopenharmony_ci		printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		if (print_ip)
22862306a36Sopenharmony_ci			printed += fprintf(fp, "%16" PRIx64, sample->ip);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		if (print_sym) {
23162306a36Sopenharmony_ci			printed += fprintf(fp, " ");
23262306a36Sopenharmony_ci			if (print_symoffset) {
23362306a36Sopenharmony_ci				printed += __symbol__fprintf_symname_offs(al->sym, al,
23462306a36Sopenharmony_ci									  print_unknown_as_addr,
23562306a36Sopenharmony_ci									  true, fp);
23662306a36Sopenharmony_ci			} else {
23762306a36Sopenharmony_ci				printed += __symbol__fprintf_symname(al->sym, al,
23862306a36Sopenharmony_ci								     print_unknown_as_addr, fp);
23962306a36Sopenharmony_ci			}
24062306a36Sopenharmony_ci		}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci		if (print_dso)
24362306a36Sopenharmony_ci			printed += map__fprintf_dsoname_dsoff(al->map, print_dsoff, al->addr, fp);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		if (print_srcline)
24662306a36Sopenharmony_ci			printed += map__fprintf_srcline(al->map, al->addr, "\n  ", fp);
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return printed;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci#endif /* PYTHON_PERF */
252