258 lines · 6.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include <inttypes.h>#include <stdio.h>#include <stdbool.h>#include "util/evlist.h"#include "evsel.h"#include "util/evsel_fprintf.h"#include "util/event.h"#include "callchain.h"#include "map.h"#include "strlist.h"#include "symbol.h"#include "srcline.h"#include "dso.h" #ifdef HAVE_LIBTRACEEVENT#include <event-parse.h>#endif static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...){	va_list args;	int ret = 0; 	if (!*first) {		ret += fprintf(fp, ",");	} else {		ret += fprintf(fp, ":");		*first = false;	} 	va_start(args, fmt);	ret += vfprintf(fp, fmt, args);	va_end(args);	return ret;} static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv){	return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val);} int evsel__fprintf(struct evsel *evsel, struct perf_attr_details *details, FILE *fp){	bool first = true;	int printed = 0; 	if (details->event_group) {		struct evsel *pos; 		if (!evsel__is_group_leader(evsel))			return 0; 		if (evsel->core.nr_members > 1)			printed += fprintf(fp, "%s{", evsel->group_name ?: ""); 		printed += fprintf(fp, "%s", evsel__name(evsel));		for_each_group_member(pos, evsel)			printed += fprintf(fp, ",%s", evsel__name(pos)); 		if (evsel->core.nr_members > 1)			printed += fprintf(fp, "}");		goto out;	} 	printed += fprintf(fp, "%s", evsel__name(evsel)); 	if (details->verbose) {		printed += perf_event_attr__fprintf(fp, &evsel->core.attr,						    __print_attr__fprintf, &first);	} else if (details->freq) {		const char *term = "sample_freq"; 		if (!evsel->core.attr.freq)			term = "sample_period"; 		printed += comma_fprintf(fp, &first, " %s=%" PRIu64,					 term, (u64)evsel->core.attr.sample_freq);	} #ifdef HAVE_LIBTRACEEVENT	if (details->trace_fields) {		struct tep_format_field *field;		const struct tep_event *tp_format; 		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) {			printed += comma_fprintf(fp, &first, " (not a tracepoint)");			goto out;		} 		tp_format = evsel__tp_format(evsel);		field = tp_format ? tp_format->format.fields : NULL;		if (field == NULL) {			printed += comma_fprintf(fp, &first, " (no trace field)");			goto out;		} 		printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name); 		field = field->next;		while (field) {			printed += comma_fprintf(fp, &first, "%s", field->name);			field = field->next;		}	}#endifout:	fputc('\n', fp);	return ++printed;} int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,			      unsigned int print_opts, struct callchain_cursor *cursor,			      struct strlist *bt_stop_list, FILE *fp){	int printed = 0;	struct callchain_cursor_node *node;	int print_ip = print_opts & EVSEL__PRINT_IP;	int print_sym = print_opts & EVSEL__PRINT_SYM;	int print_dso = print_opts & EVSEL__PRINT_DSO;	int print_dsoff = print_opts & EVSEL__PRINT_DSOFF;	int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;	int print_oneline = print_opts & EVSEL__PRINT_ONELINE;	int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;	int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;	int print_arrow = print_opts & EVSEL__PRINT_CALLCHAIN_ARROW;	int print_skip_ignored = print_opts & EVSEL__PRINT_SKIP_IGNORED;	char s = print_oneline ? ' ' : '\t';	bool first = true; 	if (cursor == NULL)		return fprintf(fp, "<not enough memory for the callchain cursor>%s", print_oneline ? "" : "\n"); 	if (sample->callchain) {		callchain_cursor_commit(cursor); 		while (1) {			struct symbol *sym;			struct map *map;			u64 addr = 0; 			node = callchain_cursor_current(cursor);			if (!node)				break; 			sym = node->ms.sym;			map = node->ms.map; 			if (sym && symbol__ignore(sym) && print_skip_ignored)				goto next; 			printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); 			if (print_arrow && !first)				printed += fprintf(fp, " <-"); 			if (map)				addr = map__map_ip(map, node->ip); 			if (print_ip)				printed += fprintf(fp, "%c%16" PRIx64, s, node->ip); 			if (print_sym) {				struct addr_location node_al; 				addr_location__init(&node_al);				printed += fprintf(fp, " ");				node_al.addr = addr;				node_al.map  = map__get(map); 				if (sample->deferred_callchain &&				    sample->deferred_cookie == node->ip) {					printed += fprintf(fp, "(cookie)");				} else if (print_symoffset) {					printed += __symbol__fprintf_symname_offs(sym, &node_al,										  print_unknown_as_addr,										  true, fp);				} else {					printed += __symbol__fprintf_symname(sym, &node_al,									     print_unknown_as_addr, fp);				}				addr_location__exit(&node_al);			} 			if (print_dso && (!sym || !symbol__inlined(sym)))				printed += map__fprintf_dsoname_dsoff(map, print_dsoff, addr, fp); 			if (print_srcline) {				if (node->srcline)					printed += fprintf(fp, "\n  %s", node->srcline);				else					printed += map__fprintf_srcline(map, addr, "\n  ", fp);			} 			if (sym && symbol__inlined(sym))				printed += fprintf(fp, " (inlined)"); 			if (!print_oneline)				printed += fprintf(fp, "\n"); 			/* Add srccode here too? */			if (bt_stop_list && sym &&			    strlist__has_entry(bt_stop_list, sym->name)) {				break;			} 			first = false;next:			callchain_cursor_advance(cursor);		}	} 	return printed;} int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,			int left_alignment, unsigned int print_opts,			struct callchain_cursor *cursor, struct strlist *bt_stop_list, FILE *fp){	int printed = 0;	int print_ip = print_opts & EVSEL__PRINT_IP;	int print_sym = print_opts & EVSEL__PRINT_SYM;	int print_dso = print_opts & EVSEL__PRINT_DSO;	int print_dsoff = print_opts & EVSEL__PRINT_DSOFF;	int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;	int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;	int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; 	if (cursor != NULL) {		printed += sample__fprintf_callchain(sample, left_alignment, print_opts,						     cursor, bt_stop_list, fp);	} else {		printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); 		if (print_ip)			printed += fprintf(fp, "%16" PRIx64, sample->ip); 		if (print_sym) {			printed += fprintf(fp, " ");			if (print_symoffset) {				printed += __symbol__fprintf_symname_offs(al->sym, al,									  print_unknown_as_addr,									  true, fp);			} else {				printed += __symbol__fprintf_symname(al->sym, al,								     print_unknown_as_addr, fp);			}		} 		if (print_dso)			printed += map__fprintf_dsoname_dsoff(al->map, print_dsoff, al->addr, fp); 		if (print_srcline)			printed += map__fprintf_srcline(al->map, al->addr, "\n  ", fp);	} 	return printed;}