diff options
Diffstat (limited to 'tools/perf/util/scripting-engines/trace-event-perl.c')
| -rw-r--r-- | tools/perf/util/scripting-engines/trace-event-perl.c | 114 | 
1 files changed, 106 insertions, 8 deletions
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index b3aabc0d4eb0..1d160855cda9 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -31,6 +31,8 @@  #include <perl.h>  #include "../../perf.h" +#include "../callchain.h" +#include "../machine.h"  #include "../thread.h"  #include "../event.h"  #include "../trace-event.h" @@ -248,10 +250,78 @@ static void define_event_symbols(struct event_format *event,  		define_event_symbols(event, ev_name, args->next);  } +static SV *perl_process_callchain(struct perf_sample *sample, +				  struct perf_evsel *evsel, +				  struct addr_location *al) +{ +	AV *list; + +	list = newAV(); +	if (!list) +		goto exit; + +	if (!symbol_conf.use_callchain || !sample->callchain) +		goto exit; + +	if (thread__resolve_callchain(al->thread, evsel, +				      sample, NULL, NULL, +				      PERF_MAX_STACK_DEPTH) != 0) { +		pr_err("Failed to resolve callchain. Skipping\n"); +		goto exit; +	} +	callchain_cursor_commit(&callchain_cursor); + + +	while (1) { +		HV *elem; +		struct callchain_cursor_node *node; +		node = callchain_cursor_current(&callchain_cursor); +		if (!node) +			break; + +		elem = newHV(); +		if (!elem) +			goto exit; + +		hv_stores(elem, "ip", newSVuv(node->ip)); + +		if (node->sym) { +			HV *sym = newHV(); +			if (!sym) +				goto exit; +			hv_stores(sym, "start",   newSVuv(node->sym->start)); +			hv_stores(sym, "end",     newSVuv(node->sym->end)); +			hv_stores(sym, "binding", newSVuv(node->sym->binding)); +			hv_stores(sym, "name",    newSVpvn(node->sym->name, +							   node->sym->namelen)); +			hv_stores(elem, "sym",    newRV_noinc((SV*)sym)); +		} + +		if (node->map) { +			struct map *map = node->map; +			const char *dsoname = "[unknown]"; +			if (map && map->dso && (map->dso->name || map->dso->long_name)) { +				if (symbol_conf.show_kernel_path && map->dso->long_name) +					dsoname = map->dso->long_name; +				else if (map->dso->name) +					dsoname = map->dso->name; +			} +			hv_stores(elem, "dso", newSVpv(dsoname,0)); +		} + +		callchain_cursor_advance(&callchain_cursor); +		av_push(list, newRV_noinc((SV*)elem)); +	} + +exit: +	return newRV_noinc((SV*)list); +} +  static void perl_process_tracepoint(struct perf_sample *sample,  				    struct perf_evsel *evsel, -				    struct thread *thread) +				    struct addr_location *al)  { +	struct thread *thread = al->thread;  	struct event_format *event = evsel->tp_format;  	struct format_field *field;  	static char handler[256]; @@ -295,6 +365,7 @@ static void perl_process_tracepoint(struct perf_sample *sample,  	XPUSHs(sv_2mortal(newSVuv(ns)));  	XPUSHs(sv_2mortal(newSViv(pid)));  	XPUSHs(sv_2mortal(newSVpv(comm, 0))); +	XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al)));  	/* common fields other than pid can be accessed via xsub fns */ @@ -329,6 +400,7 @@ static void perl_process_tracepoint(struct perf_sample *sample,  		XPUSHs(sv_2mortal(newSVuv(nsecs)));  		XPUSHs(sv_2mortal(newSViv(pid)));  		XPUSHs(sv_2mortal(newSVpv(comm, 0))); +		XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al)));  		call_pv("main::trace_unhandled", G_SCALAR);  	}  	SPAGAIN; @@ -366,7 +438,7 @@ static void perl_process_event(union perf_event *event,  			       struct perf_evsel *evsel,  			       struct addr_location *al)  { -	perl_process_tracepoint(sample, evsel, al->thread); +	perl_process_tracepoint(sample, evsel, al);  	perl_process_event_generic(event, sample, evsel);  } @@ -490,7 +562,27 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)  	fprintf(ofp, "use Perf::Trace::Util;\n\n");  	fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); -	fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n"); +	fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n"); + + +	fprintf(ofp, "\n\ +sub print_backtrace\n\ +{\n\ +	my $callchain = shift;\n\ +	for my $node (@$callchain)\n\ +	{\n\ +		if(exists $node->{sym})\n\ +		{\n\ +			printf( \"\\t[\\%%x] \\%%s\\n\", $node->{ip}, $node->{sym}{name});\n\ +		}\n\ +		else\n\ +		{\n\ +			printf( \"\\t[\\%%x]\\n\", $node{ip});\n\ +		}\n\ +	}\n\ +}\n\n\ +"); +  	while ((event = trace_find_next_event(pevent, event))) {  		fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); @@ -502,7 +594,8 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)  		fprintf(ofp, "$common_secs, ");  		fprintf(ofp, "$common_nsecs,\n");  		fprintf(ofp, "\t    $common_pid, "); -		fprintf(ofp, "$common_comm,\n\t    "); +		fprintf(ofp, "$common_comm, "); +		fprintf(ofp, "$common_callchain,\n\t    ");  		not_first = 0;  		count = 0; @@ -519,7 +612,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)  		fprintf(ofp, "\tprint_header($event_name, $common_cpu, "  			"$common_secs, $common_nsecs,\n\t             " -			"$common_pid, $common_comm);\n\n"); +			"$common_pid, $common_comm, $common_callchain);\n\n");  		fprintf(ofp, "\tprintf(\""); @@ -581,17 +674,22 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile)  				fprintf(ofp, "$%s", f->name);  		} -		fprintf(ofp, ");\n"); +		fprintf(ofp, ");\n\n"); + +		fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); +  		fprintf(ofp, "}\n\n");  	}  	fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, "  		"$common_cpu, $common_secs, $common_nsecs,\n\t    " -		"$common_pid, $common_comm) = @_;\n\n"); +		"$common_pid, $common_comm, $common_callchain) = @_;\n\n");  	fprintf(ofp, "\tprint_header($event_name, $common_cpu, "  		"$common_secs, $common_nsecs,\n\t             $common_pid, " -		"$common_comm);\n}\n\n"); +		"$common_comm, $common_callchain);\n"); +	fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); +	fprintf(ofp, "}\n\n");  	fprintf(ofp, "sub print_header\n{\n"  		"\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"  | 
