xref: /openbmc/linux/tools/perf/util/debug.c (revision 215a0d30)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2cd84c2acSFrederic Weisbecker /* For general debugging purposes */
3cd84c2acSFrederic Weisbecker 
4cd84c2acSFrederic Weisbecker #include "../perf.h"
58f28827aSFrederic Weisbecker 
6fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
7cd84c2acSFrederic Weisbecker #include <string.h>
8cd84c2acSFrederic Weisbecker #include <stdarg.h>
9cd84c2acSFrederic Weisbecker #include <stdio.h>
10215a0d30SArnaldo Carvalho de Melo #include <stdlib.h>
114208735dSArnaldo Carvalho de Melo #include <sys/wait.h>
12dd629cc0SJiri Olsa #include <api/debug.h>
13bd48c63eSArnaldo Carvalho de Melo #include <linux/time64.h>
148c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT
158c2b7cacSArnaldo Carvalho de Melo #include <execinfo.h>
168c2b7cacSArnaldo Carvalho de Melo #endif
17f9224c5cSArnaldo Carvalho de Melo #include "cache.h"
188f28827aSFrederic Weisbecker #include "color.h"
198f28827aSFrederic Weisbecker #include "event.h"
208f28827aSFrederic Weisbecker #include "debug.h"
21fea01392SArnaldo Carvalho de Melo #include "print_binary.h"
224a58e611SArnaldo Carvalho de Melo #include "util.h"
2316ad2ffbSNamhyung Kim #include "target.h"
248f28827aSFrederic Weisbecker 
253052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h>
263d689ed6SArnaldo Carvalho de Melo 
27b44308f5SArnaldo Carvalho de Melo int verbose;
28b44308f5SArnaldo Carvalho de Melo bool dump_trace = false, quiet = false;
29cee3ab9cSJiri Olsa int debug_ordered_events;
30f78eaef0SAndi Kleen static int redirect_to_stderr;
31edbe9817SJiri Olsa int debug_data_convert;
32cd84c2acSFrederic Weisbecker 
33bedbdd42SArnaldo Carvalho de Melo int veprintf(int level, int var, const char *fmt, va_list args)
34cd84c2acSFrederic Weisbecker {
35cd84c2acSFrederic Weisbecker 	int ret = 0;
36cd84c2acSFrederic Weisbecker 
37c95688aaSJiri Olsa 	if (var >= level) {
38f78eaef0SAndi Kleen 		if (use_browser >= 1 && !redirect_to_stderr)
39b56e5331SNamhyung Kim 			ui_helpline__vshow(fmt, args);
40f9224c5cSArnaldo Carvalho de Melo 		else
41cd84c2acSFrederic Weisbecker 			ret = vfprintf(stderr, fmt, args);
42cd84c2acSFrederic Weisbecker 	}
43cd84c2acSFrederic Weisbecker 
44cd84c2acSFrederic Weisbecker 	return ret;
45cd84c2acSFrederic Weisbecker }
462cec19d9SFrederic Weisbecker 
47c95688aaSJiri Olsa int eprintf(int level, int var, const char *fmt, ...)
48f772abc6SJiri Olsa {
49f772abc6SJiri Olsa 	va_list args;
50f772abc6SJiri Olsa 	int ret;
51f772abc6SJiri Olsa 
52f772abc6SJiri Olsa 	va_start(args, fmt);
53bedbdd42SArnaldo Carvalho de Melo 	ret = veprintf(level, var, fmt, args);
54f772abc6SJiri Olsa 	va_end(args);
55f772abc6SJiri Olsa 
56f772abc6SJiri Olsa 	return ret;
57f772abc6SJiri Olsa }
58f772abc6SJiri Olsa 
59bedbdd42SArnaldo Carvalho de Melo static int veprintf_time(u64 t, const char *fmt, va_list args)
60cee3ab9cSJiri Olsa {
61cee3ab9cSJiri Olsa 	int ret = 0;
62cee3ab9cSJiri Olsa 	u64 secs, usecs, nsecs = t;
63cee3ab9cSJiri Olsa 
64bd48c63eSArnaldo Carvalho de Melo 	secs   = nsecs / NSEC_PER_SEC;
65bd48c63eSArnaldo Carvalho de Melo 	nsecs -= secs  * NSEC_PER_SEC;
66bd48c63eSArnaldo Carvalho de Melo 	usecs  = nsecs / NSEC_PER_USEC;
67cee3ab9cSJiri Olsa 
68cee3ab9cSJiri Olsa 	ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
69cee3ab9cSJiri Olsa 		      secs, usecs);
70cee3ab9cSJiri Olsa 	ret += vfprintf(stderr, fmt, args);
71cee3ab9cSJiri Olsa 	return ret;
72cee3ab9cSJiri Olsa }
73cee3ab9cSJiri Olsa 
74cee3ab9cSJiri Olsa int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
75cee3ab9cSJiri Olsa {
76cee3ab9cSJiri Olsa 	int ret = 0;
77cee3ab9cSJiri Olsa 	va_list args;
78cee3ab9cSJiri Olsa 
79cee3ab9cSJiri Olsa 	if (var >= level) {
80cee3ab9cSJiri Olsa 		va_start(args, fmt);
81bedbdd42SArnaldo Carvalho de Melo 		ret = veprintf_time(t, fmt, args);
82cee3ab9cSJiri Olsa 		va_end(args);
83cee3ab9cSJiri Olsa 	}
84cee3ab9cSJiri Olsa 
85cee3ab9cSJiri Olsa 	return ret;
86cee3ab9cSJiri Olsa }
87cee3ab9cSJiri Olsa 
88f772abc6SJiri Olsa /*
89f772abc6SJiri Olsa  * Overloading libtraceevent standard info print
90f772abc6SJiri Olsa  * function, display with -v in perf.
91f772abc6SJiri Olsa  */
92f772abc6SJiri Olsa void pr_stat(const char *fmt, ...)
93f772abc6SJiri Olsa {
94f772abc6SJiri Olsa 	va_list args;
95f772abc6SJiri Olsa 
96f772abc6SJiri Olsa 	va_start(args, fmt);
97bedbdd42SArnaldo Carvalho de Melo 	veprintf(1, verbose, fmt, args);
98f772abc6SJiri Olsa 	va_end(args);
99c95688aaSJiri Olsa 	eprintf(1, verbose, "\n");
100f772abc6SJiri Olsa }
101f772abc6SJiri Olsa 
1022cec19d9SFrederic Weisbecker int dump_printf(const char *fmt, ...)
1032cec19d9SFrederic Weisbecker {
1042cec19d9SFrederic Weisbecker 	va_list args;
1052cec19d9SFrederic Weisbecker 	int ret = 0;
1062cec19d9SFrederic Weisbecker 
1072cec19d9SFrederic Weisbecker 	if (dump_trace) {
1082cec19d9SFrederic Weisbecker 		va_start(args, fmt);
1092cec19d9SFrederic Weisbecker 		ret = vprintf(fmt, args);
1102cec19d9SFrederic Weisbecker 		va_end(args);
1112cec19d9SFrederic Weisbecker 	}
1122cec19d9SFrederic Weisbecker 
1132cec19d9SFrederic Weisbecker 	return ret;
1142cec19d9SFrederic Weisbecker }
1158f28827aSFrederic Weisbecker 
116923d0c9aSArnaldo Carvalho de Melo static int trace_event_printer(enum binary_printer_ops op,
117923d0c9aSArnaldo Carvalho de Melo 			       unsigned int val, void *extra, FILE *fp)
118c339b1a9SWang Nan {
119c339b1a9SWang Nan 	const char *color = PERF_COLOR_BLUE;
120c339b1a9SWang Nan 	union perf_event *event = (union perf_event *)extra;
121c339b1a9SWang Nan 	unsigned char ch = (unsigned char)val;
122923d0c9aSArnaldo Carvalho de Melo 	int printed = 0;
123c339b1a9SWang Nan 
124c339b1a9SWang Nan 	switch (op) {
125c339b1a9SWang Nan 	case BINARY_PRINT_DATA_BEGIN:
126923d0c9aSArnaldo Carvalho de Melo 		printed += fprintf(fp, ".");
127923d0c9aSArnaldo Carvalho de Melo 		printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n",
128c339b1a9SWang Nan 					 event->header.size);
129c339b1a9SWang Nan 		break;
130c339b1a9SWang Nan 	case BINARY_PRINT_LINE_BEGIN:
131923d0c9aSArnaldo Carvalho de Melo 		printed += fprintf(fp, ".");
132c339b1a9SWang Nan 		break;
133c339b1a9SWang Nan 	case BINARY_PRINT_ADDR:
134923d0c9aSArnaldo Carvalho de Melo 		printed += color_fprintf(fp, color, "  %04x: ", val);
135c339b1a9SWang Nan 		break;
136c339b1a9SWang Nan 	case BINARY_PRINT_NUM_DATA:
137923d0c9aSArnaldo Carvalho de Melo 		printed += color_fprintf(fp, color, " %02x", val);
138c339b1a9SWang Nan 		break;
139c339b1a9SWang Nan 	case BINARY_PRINT_NUM_PAD:
140923d0c9aSArnaldo Carvalho de Melo 		printed += color_fprintf(fp, color, "   ");
141c339b1a9SWang Nan 		break;
142c339b1a9SWang Nan 	case BINARY_PRINT_SEP:
143923d0c9aSArnaldo Carvalho de Melo 		printed += color_fprintf(fp, color, "  ");
144c339b1a9SWang Nan 		break;
145c339b1a9SWang Nan 	case BINARY_PRINT_CHAR_DATA:
146923d0c9aSArnaldo Carvalho de Melo 		printed += color_fprintf(fp, color, "%c",
147c339b1a9SWang Nan 			      isprint(ch) ? ch : '.');
148c339b1a9SWang Nan 		break;
149c339b1a9SWang Nan 	case BINARY_PRINT_CHAR_PAD:
150923d0c9aSArnaldo Carvalho de Melo 		printed += color_fprintf(fp, color, " ");
151c339b1a9SWang Nan 		break;
152c339b1a9SWang Nan 	case BINARY_PRINT_LINE_END:
153923d0c9aSArnaldo Carvalho de Melo 		printed += color_fprintf(fp, color, "\n");
154c339b1a9SWang Nan 		break;
155c339b1a9SWang Nan 	case BINARY_PRINT_DATA_END:
156923d0c9aSArnaldo Carvalho de Melo 		printed += fprintf(fp, "\n");
157c339b1a9SWang Nan 		break;
158c339b1a9SWang Nan 	default:
159c339b1a9SWang Nan 		break;
160c339b1a9SWang Nan 	}
161923d0c9aSArnaldo Carvalho de Melo 
162923d0c9aSArnaldo Carvalho de Melo 	return printed;
163c339b1a9SWang Nan }
164c339b1a9SWang Nan 
1658115d60cSArnaldo Carvalho de Melo void trace_event(union perf_event *event)
1668f28827aSFrederic Weisbecker {
1678f28827aSFrederic Weisbecker 	unsigned char *raw_event = (void *)event;
1688f28827aSFrederic Weisbecker 
1698f28827aSFrederic Weisbecker 	if (!dump_trace)
1708f28827aSFrederic Weisbecker 		return;
1718f28827aSFrederic Weisbecker 
172c339b1a9SWang Nan 	print_binary(raw_event, event->header.size, 16,
173c339b1a9SWang Nan 		     trace_event_printer, event);
1748f28827aSFrederic Weisbecker }
175bbb2cea7SJiri Olsa 
176bbb2cea7SJiri Olsa static struct debug_variable {
177bbb2cea7SJiri Olsa 	const char *name;
178bbb2cea7SJiri Olsa 	int *ptr;
179bbb2cea7SJiri Olsa } debug_variables[] = {
180bbb2cea7SJiri Olsa 	{ .name = "verbose",		.ptr = &verbose },
181cee3ab9cSJiri Olsa 	{ .name = "ordered-events",	.ptr = &debug_ordered_events},
182f78eaef0SAndi Kleen 	{ .name = "stderr",		.ptr = &redirect_to_stderr},
183edbe9817SJiri Olsa 	{ .name = "data-convert",	.ptr = &debug_data_convert },
184bbb2cea7SJiri Olsa 	{ .name = NULL, }
185bbb2cea7SJiri Olsa };
186bbb2cea7SJiri Olsa 
187bbb2cea7SJiri Olsa int perf_debug_option(const char *str)
188bbb2cea7SJiri Olsa {
189bbb2cea7SJiri Olsa 	struct debug_variable *var = &debug_variables[0];
190bbb2cea7SJiri Olsa 	char *vstr, *s = strdup(str);
191bbb2cea7SJiri Olsa 	int v = 1;
192bbb2cea7SJiri Olsa 
193bbb2cea7SJiri Olsa 	vstr = strchr(s, '=');
194bbb2cea7SJiri Olsa 	if (vstr)
195bbb2cea7SJiri Olsa 		*vstr++ = 0;
196bbb2cea7SJiri Olsa 
197bbb2cea7SJiri Olsa 	while (var->name) {
198bbb2cea7SJiri Olsa 		if (!strcmp(s, var->name))
199bbb2cea7SJiri Olsa 			break;
200bbb2cea7SJiri Olsa 		var++;
201bbb2cea7SJiri Olsa 	}
202bbb2cea7SJiri Olsa 
203bbb2cea7SJiri Olsa 	if (!var->name) {
204bbb2cea7SJiri Olsa 		pr_err("Unknown debug variable name '%s'\n", s);
205bbb2cea7SJiri Olsa 		free(s);
206bbb2cea7SJiri Olsa 		return -1;
207bbb2cea7SJiri Olsa 	}
208bbb2cea7SJiri Olsa 
209bbb2cea7SJiri Olsa 	if (vstr) {
210bbb2cea7SJiri Olsa 		v = atoi(vstr);
211bbb2cea7SJiri Olsa 		/*
212bbb2cea7SJiri Olsa 		 * Allow only values in range (0, 10),
213bbb2cea7SJiri Olsa 		 * otherwise set 0.
214bbb2cea7SJiri Olsa 		 */
215bbb2cea7SJiri Olsa 		v = (v < 0) || (v > 10) ? 0 : v;
216bbb2cea7SJiri Olsa 	}
217bbb2cea7SJiri Olsa 
21880df1988SNamhyung Kim 	if (quiet)
21980df1988SNamhyung Kim 		v = -1;
22080df1988SNamhyung Kim 
221bbb2cea7SJiri Olsa 	*var->ptr = v;
222bbb2cea7SJiri Olsa 	free(s);
223bbb2cea7SJiri Olsa 	return 0;
224bbb2cea7SJiri Olsa }
225dd629cc0SJiri Olsa 
22680df1988SNamhyung Kim int perf_quiet_option(void)
22780df1988SNamhyung Kim {
22880df1988SNamhyung Kim 	struct debug_variable *var = &debug_variables[0];
22980df1988SNamhyung Kim 
23080df1988SNamhyung Kim 	/* disable all debug messages */
23180df1988SNamhyung Kim 	while (var->name) {
23280df1988SNamhyung Kim 		*var->ptr = -1;
23380df1988SNamhyung Kim 		var++;
23480df1988SNamhyung Kim 	}
23580df1988SNamhyung Kim 
23680df1988SNamhyung Kim 	return 0;
23780df1988SNamhyung Kim }
23880df1988SNamhyung Kim 
239dd629cc0SJiri Olsa #define DEBUG_WRAPPER(__n, __l)				\
240dd629cc0SJiri Olsa static int pr_ ## __n ## _wrapper(const char *fmt, ...)	\
241dd629cc0SJiri Olsa {							\
242dd629cc0SJiri Olsa 	va_list args;					\
243dd629cc0SJiri Olsa 	int ret;					\
244dd629cc0SJiri Olsa 							\
245dd629cc0SJiri Olsa 	va_start(args, fmt);				\
246dd629cc0SJiri Olsa 	ret = veprintf(__l, verbose, fmt, args);	\
247dd629cc0SJiri Olsa 	va_end(args);					\
248dd629cc0SJiri Olsa 	return ret;					\
249dd629cc0SJiri Olsa }
250dd629cc0SJiri Olsa 
251dd629cc0SJiri Olsa DEBUG_WRAPPER(warning, 0);
252dd629cc0SJiri Olsa DEBUG_WRAPPER(debug, 1);
253dd629cc0SJiri Olsa 
254dd629cc0SJiri Olsa void perf_debug_setup(void)
255dd629cc0SJiri Olsa {
256dd629cc0SJiri Olsa 	libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
257dd629cc0SJiri Olsa }
2588c2b7cacSArnaldo Carvalho de Melo 
2598c2b7cacSArnaldo Carvalho de Melo /* Obtain a backtrace and print it to stdout. */
2608c2b7cacSArnaldo Carvalho de Melo #ifdef HAVE_BACKTRACE_SUPPORT
2618c2b7cacSArnaldo Carvalho de Melo void dump_stack(void)
2628c2b7cacSArnaldo Carvalho de Melo {
2638c2b7cacSArnaldo Carvalho de Melo 	void *array[16];
2648c2b7cacSArnaldo Carvalho de Melo 	size_t size = backtrace(array, ARRAY_SIZE(array));
2658c2b7cacSArnaldo Carvalho de Melo 	char **strings = backtrace_symbols(array, size);
2668c2b7cacSArnaldo Carvalho de Melo 	size_t i;
2678c2b7cacSArnaldo Carvalho de Melo 
2688c2b7cacSArnaldo Carvalho de Melo 	printf("Obtained %zd stack frames.\n", size);
2698c2b7cacSArnaldo Carvalho de Melo 
2708c2b7cacSArnaldo Carvalho de Melo 	for (i = 0; i < size; i++)
2718c2b7cacSArnaldo Carvalho de Melo 		printf("%s\n", strings[i]);
2728c2b7cacSArnaldo Carvalho de Melo 
2738c2b7cacSArnaldo Carvalho de Melo 	free(strings);
2748c2b7cacSArnaldo Carvalho de Melo }
2758c2b7cacSArnaldo Carvalho de Melo #else
2768c2b7cacSArnaldo Carvalho de Melo void dump_stack(void) {}
2778c2b7cacSArnaldo Carvalho de Melo #endif
2788c2b7cacSArnaldo Carvalho de Melo 
2798c2b7cacSArnaldo Carvalho de Melo void sighandler_dump_stack(int sig)
2808c2b7cacSArnaldo Carvalho de Melo {
2818c2b7cacSArnaldo Carvalho de Melo 	psignal(sig, "perf");
2828c2b7cacSArnaldo Carvalho de Melo 	dump_stack();
2838c2b7cacSArnaldo Carvalho de Melo 	signal(sig, SIG_DFL);
2848c2b7cacSArnaldo Carvalho de Melo 	raise(sig);
2858c2b7cacSArnaldo Carvalho de Melo }
286