xref: /openbmc/linux/tools/perf/util/debug.c (revision 4208735d)
1cd84c2acSFrederic Weisbecker /* For general debugging purposes */
2cd84c2acSFrederic Weisbecker 
3cd84c2acSFrederic Weisbecker #include "../perf.h"
48f28827aSFrederic Weisbecker 
5fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
6cd84c2acSFrederic Weisbecker #include <string.h>
7cd84c2acSFrederic Weisbecker #include <stdarg.h>
8cd84c2acSFrederic Weisbecker #include <stdio.h>
94208735dSArnaldo Carvalho de Melo #include <sys/wait.h>
10dd629cc0SJiri Olsa #include <api/debug.h>
11bd48c63eSArnaldo Carvalho de Melo #include <linux/time64.h>
128c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT
138c2b7cacSArnaldo Carvalho de Melo #include <execinfo.h>
148c2b7cacSArnaldo Carvalho de Melo #endif
15f9224c5cSArnaldo Carvalho de Melo #include "cache.h"
168f28827aSFrederic Weisbecker #include "color.h"
178f28827aSFrederic Weisbecker #include "event.h"
188f28827aSFrederic Weisbecker #include "debug.h"
19fea01392SArnaldo Carvalho de Melo #include "print_binary.h"
204a58e611SArnaldo Carvalho de Melo #include "util.h"
2116ad2ffbSNamhyung Kim #include "target.h"
228f28827aSFrederic Weisbecker 
233d689ed6SArnaldo Carvalho de Melo #include "sane_ctype.h"
243d689ed6SArnaldo Carvalho de Melo 
25b44308f5SArnaldo Carvalho de Melo int verbose;
26b44308f5SArnaldo Carvalho de Melo bool dump_trace = false, quiet = false;
27cee3ab9cSJiri Olsa int debug_ordered_events;
28f78eaef0SAndi Kleen static int redirect_to_stderr;
29edbe9817SJiri Olsa int debug_data_convert;
30cd84c2acSFrederic Weisbecker 
31bedbdd42SArnaldo Carvalho de Melo int veprintf(int level, int var, const char *fmt, va_list args)
32cd84c2acSFrederic Weisbecker {
33cd84c2acSFrederic Weisbecker 	int ret = 0;
34cd84c2acSFrederic Weisbecker 
35c95688aaSJiri Olsa 	if (var >= level) {
36f78eaef0SAndi Kleen 		if (use_browser >= 1 && !redirect_to_stderr)
37b56e5331SNamhyung Kim 			ui_helpline__vshow(fmt, args);
38f9224c5cSArnaldo Carvalho de Melo 		else
39cd84c2acSFrederic Weisbecker 			ret = vfprintf(stderr, fmt, args);
40cd84c2acSFrederic Weisbecker 	}
41cd84c2acSFrederic Weisbecker 
42cd84c2acSFrederic Weisbecker 	return ret;
43cd84c2acSFrederic Weisbecker }
442cec19d9SFrederic Weisbecker 
45c95688aaSJiri Olsa int eprintf(int level, int var, const char *fmt, ...)
46f772abc6SJiri Olsa {
47f772abc6SJiri Olsa 	va_list args;
48f772abc6SJiri Olsa 	int ret;
49f772abc6SJiri Olsa 
50f772abc6SJiri Olsa 	va_start(args, fmt);
51bedbdd42SArnaldo Carvalho de Melo 	ret = veprintf(level, var, fmt, args);
52f772abc6SJiri Olsa 	va_end(args);
53f772abc6SJiri Olsa 
54f772abc6SJiri Olsa 	return ret;
55f772abc6SJiri Olsa }
56f772abc6SJiri Olsa 
57bedbdd42SArnaldo Carvalho de Melo static int veprintf_time(u64 t, const char *fmt, va_list args)
58cee3ab9cSJiri Olsa {
59cee3ab9cSJiri Olsa 	int ret = 0;
60cee3ab9cSJiri Olsa 	u64 secs, usecs, nsecs = t;
61cee3ab9cSJiri Olsa 
62bd48c63eSArnaldo Carvalho de Melo 	secs   = nsecs / NSEC_PER_SEC;
63bd48c63eSArnaldo Carvalho de Melo 	nsecs -= secs  * NSEC_PER_SEC;
64bd48c63eSArnaldo Carvalho de Melo 	usecs  = nsecs / NSEC_PER_USEC;
65cee3ab9cSJiri Olsa 
66cee3ab9cSJiri Olsa 	ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
67cee3ab9cSJiri Olsa 		      secs, usecs);
68cee3ab9cSJiri Olsa 	ret += vfprintf(stderr, fmt, args);
69cee3ab9cSJiri Olsa 	return ret;
70cee3ab9cSJiri Olsa }
71cee3ab9cSJiri Olsa 
72cee3ab9cSJiri Olsa int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
73cee3ab9cSJiri Olsa {
74cee3ab9cSJiri Olsa 	int ret = 0;
75cee3ab9cSJiri Olsa 	va_list args;
76cee3ab9cSJiri Olsa 
77cee3ab9cSJiri Olsa 	if (var >= level) {
78cee3ab9cSJiri Olsa 		va_start(args, fmt);
79bedbdd42SArnaldo Carvalho de Melo 		ret = veprintf_time(t, fmt, args);
80cee3ab9cSJiri Olsa 		va_end(args);
81cee3ab9cSJiri Olsa 	}
82cee3ab9cSJiri Olsa 
83cee3ab9cSJiri Olsa 	return ret;
84cee3ab9cSJiri Olsa }
85cee3ab9cSJiri Olsa 
86f772abc6SJiri Olsa /*
87f772abc6SJiri Olsa  * Overloading libtraceevent standard info print
88f772abc6SJiri Olsa  * function, display with -v in perf.
89f772abc6SJiri Olsa  */
90f772abc6SJiri Olsa void pr_stat(const char *fmt, ...)
91f772abc6SJiri Olsa {
92f772abc6SJiri Olsa 	va_list args;
93f772abc6SJiri Olsa 
94f772abc6SJiri Olsa 	va_start(args, fmt);
95bedbdd42SArnaldo Carvalho de Melo 	veprintf(1, verbose, fmt, args);
96f772abc6SJiri Olsa 	va_end(args);
97c95688aaSJiri Olsa 	eprintf(1, verbose, "\n");
98f772abc6SJiri Olsa }
99f772abc6SJiri Olsa 
1002cec19d9SFrederic Weisbecker int dump_printf(const char *fmt, ...)
1012cec19d9SFrederic Weisbecker {
1022cec19d9SFrederic Weisbecker 	va_list args;
1032cec19d9SFrederic Weisbecker 	int ret = 0;
1042cec19d9SFrederic Weisbecker 
1052cec19d9SFrederic Weisbecker 	if (dump_trace) {
1062cec19d9SFrederic Weisbecker 		va_start(args, fmt);
1072cec19d9SFrederic Weisbecker 		ret = vprintf(fmt, args);
1082cec19d9SFrederic Weisbecker 		va_end(args);
1092cec19d9SFrederic Weisbecker 	}
1102cec19d9SFrederic Weisbecker 
1112cec19d9SFrederic Weisbecker 	return ret;
1122cec19d9SFrederic Weisbecker }
1138f28827aSFrederic Weisbecker 
114c339b1a9SWang Nan static void trace_event_printer(enum binary_printer_ops op,
115c339b1a9SWang Nan 				unsigned int val, void *extra)
116c339b1a9SWang Nan {
117c339b1a9SWang Nan 	const char *color = PERF_COLOR_BLUE;
118c339b1a9SWang Nan 	union perf_event *event = (union perf_event *)extra;
119c339b1a9SWang Nan 	unsigned char ch = (unsigned char)val;
120c339b1a9SWang Nan 
121c339b1a9SWang Nan 	switch (op) {
122c339b1a9SWang Nan 	case BINARY_PRINT_DATA_BEGIN:
123c339b1a9SWang Nan 		printf(".");
124c339b1a9SWang Nan 		color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n",
125c339b1a9SWang Nan 				event->header.size);
126c339b1a9SWang Nan 		break;
127c339b1a9SWang Nan 	case BINARY_PRINT_LINE_BEGIN:
128c339b1a9SWang Nan 		printf(".");
129c339b1a9SWang Nan 		break;
130c339b1a9SWang Nan 	case BINARY_PRINT_ADDR:
131c339b1a9SWang Nan 		color_fprintf(stdout, color, "  %04x: ", val);
132c339b1a9SWang Nan 		break;
133c339b1a9SWang Nan 	case BINARY_PRINT_NUM_DATA:
134c339b1a9SWang Nan 		color_fprintf(stdout, color, " %02x", val);
135c339b1a9SWang Nan 		break;
136c339b1a9SWang Nan 	case BINARY_PRINT_NUM_PAD:
137c339b1a9SWang Nan 		color_fprintf(stdout, color, "   ");
138c339b1a9SWang Nan 		break;
139c339b1a9SWang Nan 	case BINARY_PRINT_SEP:
140c339b1a9SWang Nan 		color_fprintf(stdout, color, "  ");
141c339b1a9SWang Nan 		break;
142c339b1a9SWang Nan 	case BINARY_PRINT_CHAR_DATA:
143c339b1a9SWang Nan 		color_fprintf(stdout, color, "%c",
144c339b1a9SWang Nan 			      isprint(ch) ? ch : '.');
145c339b1a9SWang Nan 		break;
146c339b1a9SWang Nan 	case BINARY_PRINT_CHAR_PAD:
147c339b1a9SWang Nan 		color_fprintf(stdout, color, " ");
148c339b1a9SWang Nan 		break;
149c339b1a9SWang Nan 	case BINARY_PRINT_LINE_END:
150c339b1a9SWang Nan 		color_fprintf(stdout, color, "\n");
151c339b1a9SWang Nan 		break;
152c339b1a9SWang Nan 	case BINARY_PRINT_DATA_END:
153c339b1a9SWang Nan 		printf("\n");
154c339b1a9SWang Nan 		break;
155c339b1a9SWang Nan 	default:
156c339b1a9SWang Nan 		break;
157c339b1a9SWang Nan 	}
158c339b1a9SWang Nan }
159c339b1a9SWang Nan 
1608115d60cSArnaldo Carvalho de Melo void trace_event(union perf_event *event)
1618f28827aSFrederic Weisbecker {
1628f28827aSFrederic Weisbecker 	unsigned char *raw_event = (void *)event;
1638f28827aSFrederic Weisbecker 
1648f28827aSFrederic Weisbecker 	if (!dump_trace)
1658f28827aSFrederic Weisbecker 		return;
1668f28827aSFrederic Weisbecker 
167c339b1a9SWang Nan 	print_binary(raw_event, event->header.size, 16,
168c339b1a9SWang Nan 		     trace_event_printer, event);
1698f28827aSFrederic Weisbecker }
170bbb2cea7SJiri Olsa 
171bbb2cea7SJiri Olsa static struct debug_variable {
172bbb2cea7SJiri Olsa 	const char *name;
173bbb2cea7SJiri Olsa 	int *ptr;
174bbb2cea7SJiri Olsa } debug_variables[] = {
175bbb2cea7SJiri Olsa 	{ .name = "verbose",		.ptr = &verbose },
176cee3ab9cSJiri Olsa 	{ .name = "ordered-events",	.ptr = &debug_ordered_events},
177f78eaef0SAndi Kleen 	{ .name = "stderr",		.ptr = &redirect_to_stderr},
178edbe9817SJiri Olsa 	{ .name = "data-convert",	.ptr = &debug_data_convert },
179bbb2cea7SJiri Olsa 	{ .name = NULL, }
180bbb2cea7SJiri Olsa };
181bbb2cea7SJiri Olsa 
182bbb2cea7SJiri Olsa int perf_debug_option(const char *str)
183bbb2cea7SJiri Olsa {
184bbb2cea7SJiri Olsa 	struct debug_variable *var = &debug_variables[0];
185bbb2cea7SJiri Olsa 	char *vstr, *s = strdup(str);
186bbb2cea7SJiri Olsa 	int v = 1;
187bbb2cea7SJiri Olsa 
188bbb2cea7SJiri Olsa 	vstr = strchr(s, '=');
189bbb2cea7SJiri Olsa 	if (vstr)
190bbb2cea7SJiri Olsa 		*vstr++ = 0;
191bbb2cea7SJiri Olsa 
192bbb2cea7SJiri Olsa 	while (var->name) {
193bbb2cea7SJiri Olsa 		if (!strcmp(s, var->name))
194bbb2cea7SJiri Olsa 			break;
195bbb2cea7SJiri Olsa 		var++;
196bbb2cea7SJiri Olsa 	}
197bbb2cea7SJiri Olsa 
198bbb2cea7SJiri Olsa 	if (!var->name) {
199bbb2cea7SJiri Olsa 		pr_err("Unknown debug variable name '%s'\n", s);
200bbb2cea7SJiri Olsa 		free(s);
201bbb2cea7SJiri Olsa 		return -1;
202bbb2cea7SJiri Olsa 	}
203bbb2cea7SJiri Olsa 
204bbb2cea7SJiri Olsa 	if (vstr) {
205bbb2cea7SJiri Olsa 		v = atoi(vstr);
206bbb2cea7SJiri Olsa 		/*
207bbb2cea7SJiri Olsa 		 * Allow only values in range (0, 10),
208bbb2cea7SJiri Olsa 		 * otherwise set 0.
209bbb2cea7SJiri Olsa 		 */
210bbb2cea7SJiri Olsa 		v = (v < 0) || (v > 10) ? 0 : v;
211bbb2cea7SJiri Olsa 	}
212bbb2cea7SJiri Olsa 
21380df1988SNamhyung Kim 	if (quiet)
21480df1988SNamhyung Kim 		v = -1;
21580df1988SNamhyung Kim 
216bbb2cea7SJiri Olsa 	*var->ptr = v;
217bbb2cea7SJiri Olsa 	free(s);
218bbb2cea7SJiri Olsa 	return 0;
219bbb2cea7SJiri Olsa }
220dd629cc0SJiri Olsa 
22180df1988SNamhyung Kim int perf_quiet_option(void)
22280df1988SNamhyung Kim {
22380df1988SNamhyung Kim 	struct debug_variable *var = &debug_variables[0];
22480df1988SNamhyung Kim 
22580df1988SNamhyung Kim 	/* disable all debug messages */
22680df1988SNamhyung Kim 	while (var->name) {
22780df1988SNamhyung Kim 		*var->ptr = -1;
22880df1988SNamhyung Kim 		var++;
22980df1988SNamhyung Kim 	}
23080df1988SNamhyung Kim 
23180df1988SNamhyung Kim 	quiet = true;
23280df1988SNamhyung Kim 	return 0;
23380df1988SNamhyung Kim }
23480df1988SNamhyung Kim 
235dd629cc0SJiri Olsa #define DEBUG_WRAPPER(__n, __l)				\
236dd629cc0SJiri Olsa static int pr_ ## __n ## _wrapper(const char *fmt, ...)	\
237dd629cc0SJiri Olsa {							\
238dd629cc0SJiri Olsa 	va_list args;					\
239dd629cc0SJiri Olsa 	int ret;					\
240dd629cc0SJiri Olsa 							\
241dd629cc0SJiri Olsa 	va_start(args, fmt);				\
242dd629cc0SJiri Olsa 	ret = veprintf(__l, verbose, fmt, args);	\
243dd629cc0SJiri Olsa 	va_end(args);					\
244dd629cc0SJiri Olsa 	return ret;					\
245dd629cc0SJiri Olsa }
246dd629cc0SJiri Olsa 
247dd629cc0SJiri Olsa DEBUG_WRAPPER(warning, 0);
248dd629cc0SJiri Olsa DEBUG_WRAPPER(debug, 1);
249dd629cc0SJiri Olsa 
250dd629cc0SJiri Olsa void perf_debug_setup(void)
251dd629cc0SJiri Olsa {
252dd629cc0SJiri Olsa 	libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
253dd629cc0SJiri Olsa }
2548c2b7cacSArnaldo Carvalho de Melo 
2558c2b7cacSArnaldo Carvalho de Melo /* Obtain a backtrace and print it to stdout. */
2568c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT
2578c2b7cacSArnaldo Carvalho de Melo void dump_stack(void)
2588c2b7cacSArnaldo Carvalho de Melo {
2598c2b7cacSArnaldo Carvalho de Melo 	void *array[16];
2608c2b7cacSArnaldo Carvalho de Melo 	size_t size = backtrace(array, ARRAY_SIZE(array));
2618c2b7cacSArnaldo Carvalho de Melo 	char **strings = backtrace_symbols(array, size);
2628c2b7cacSArnaldo Carvalho de Melo 	size_t i;
2638c2b7cacSArnaldo Carvalho de Melo 
2648c2b7cacSArnaldo Carvalho de Melo 	printf("Obtained %zd stack frames.\n", size);
2658c2b7cacSArnaldo Carvalho de Melo 
2668c2b7cacSArnaldo Carvalho de Melo 	for (i = 0; i < size; i++)
2678c2b7cacSArnaldo Carvalho de Melo 		printf("%s\n", strings[i]);
2688c2b7cacSArnaldo Carvalho de Melo 
2698c2b7cacSArnaldo Carvalho de Melo 	free(strings);
2708c2b7cacSArnaldo Carvalho de Melo }
2718c2b7cacSArnaldo Carvalho de Melo #else
2728c2b7cacSArnaldo Carvalho de Melo void dump_stack(void) {}
2738c2b7cacSArnaldo Carvalho de Melo #endif
2748c2b7cacSArnaldo Carvalho de Melo 
2758c2b7cacSArnaldo Carvalho de Melo void sighandler_dump_stack(int sig)
2768c2b7cacSArnaldo Carvalho de Melo {
2778c2b7cacSArnaldo Carvalho de Melo 	psignal(sig, "perf");
2788c2b7cacSArnaldo Carvalho de Melo 	dump_stack();
2798c2b7cacSArnaldo Carvalho de Melo 	signal(sig, SIG_DFL);
2808c2b7cacSArnaldo Carvalho de Melo 	raise(sig);
2818c2b7cacSArnaldo Carvalho de Melo }
282