xref: /openbmc/linux/tools/perf/util/debug.c (revision 65db92e0965ab56e8031d5c804f26d5be0e47047)
1 /* For general debugging purposes */
2 
3 #include "../perf.h"
4 
5 #include <inttypes.h>
6 #include <string.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <sys/wait.h>
10 #include <api/debug.h>
11 #include <linux/time64.h>
12 #ifdef HAVE_BACKTRACE_SUPPORT
13 #include <execinfo.h>
14 #endif
15 #include "cache.h"
16 #include "color.h"
17 #include "event.h"
18 #include "debug.h"
19 #include "print_binary.h"
20 #include "util.h"
21 #include "target.h"
22 
23 #include "sane_ctype.h"
24 
25 int verbose;
26 bool dump_trace = false, quiet = false;
27 int debug_ordered_events;
28 static int redirect_to_stderr;
29 int debug_data_convert;
30 
31 int veprintf(int level, int var, const char *fmt, va_list args)
32 {
33 	int ret = 0;
34 
35 	if (var >= level) {
36 		if (use_browser >= 1 && !redirect_to_stderr)
37 			ui_helpline__vshow(fmt, args);
38 		else
39 			ret = vfprintf(stderr, fmt, args);
40 	}
41 
42 	return ret;
43 }
44 
45 int eprintf(int level, int var, const char *fmt, ...)
46 {
47 	va_list args;
48 	int ret;
49 
50 	va_start(args, fmt);
51 	ret = veprintf(level, var, fmt, args);
52 	va_end(args);
53 
54 	return ret;
55 }
56 
57 static int veprintf_time(u64 t, const char *fmt, va_list args)
58 {
59 	int ret = 0;
60 	u64 secs, usecs, nsecs = t;
61 
62 	secs   = nsecs / NSEC_PER_SEC;
63 	nsecs -= secs  * NSEC_PER_SEC;
64 	usecs  = nsecs / NSEC_PER_USEC;
65 
66 	ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
67 		      secs, usecs);
68 	ret += vfprintf(stderr, fmt, args);
69 	return ret;
70 }
71 
72 int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
73 {
74 	int ret = 0;
75 	va_list args;
76 
77 	if (var >= level) {
78 		va_start(args, fmt);
79 		ret = veprintf_time(t, fmt, args);
80 		va_end(args);
81 	}
82 
83 	return ret;
84 }
85 
86 /*
87  * Overloading libtraceevent standard info print
88  * function, display with -v in perf.
89  */
90 void pr_stat(const char *fmt, ...)
91 {
92 	va_list args;
93 
94 	va_start(args, fmt);
95 	veprintf(1, verbose, fmt, args);
96 	va_end(args);
97 	eprintf(1, verbose, "\n");
98 }
99 
100 int dump_printf(const char *fmt, ...)
101 {
102 	va_list args;
103 	int ret = 0;
104 
105 	if (dump_trace) {
106 		va_start(args, fmt);
107 		ret = vprintf(fmt, args);
108 		va_end(args);
109 	}
110 
111 	return ret;
112 }
113 
114 static int trace_event_printer(enum binary_printer_ops op,
115 			       unsigned int val, void *extra, FILE *fp)
116 {
117 	const char *color = PERF_COLOR_BLUE;
118 	union perf_event *event = (union perf_event *)extra;
119 	unsigned char ch = (unsigned char)val;
120 	int printed = 0;
121 
122 	switch (op) {
123 	case BINARY_PRINT_DATA_BEGIN:
124 		printed += fprintf(fp, ".");
125 		printed += color_fprintf(fp, color, "\n. ... raw event: size %d bytes\n",
126 					 event->header.size);
127 		break;
128 	case BINARY_PRINT_LINE_BEGIN:
129 		printed += fprintf(fp, ".");
130 		break;
131 	case BINARY_PRINT_ADDR:
132 		printed += color_fprintf(fp, color, "  %04x: ", val);
133 		break;
134 	case BINARY_PRINT_NUM_DATA:
135 		printed += color_fprintf(fp, color, " %02x", val);
136 		break;
137 	case BINARY_PRINT_NUM_PAD:
138 		printed += color_fprintf(fp, color, "   ");
139 		break;
140 	case BINARY_PRINT_SEP:
141 		printed += color_fprintf(fp, color, "  ");
142 		break;
143 	case BINARY_PRINT_CHAR_DATA:
144 		printed += color_fprintf(fp, color, "%c",
145 			      isprint(ch) ? ch : '.');
146 		break;
147 	case BINARY_PRINT_CHAR_PAD:
148 		printed += color_fprintf(fp, color, " ");
149 		break;
150 	case BINARY_PRINT_LINE_END:
151 		printed += color_fprintf(fp, color, "\n");
152 		break;
153 	case BINARY_PRINT_DATA_END:
154 		printed += fprintf(fp, "\n");
155 		break;
156 	default:
157 		break;
158 	}
159 
160 	return printed;
161 }
162 
163 void trace_event(union perf_event *event)
164 {
165 	unsigned char *raw_event = (void *)event;
166 
167 	if (!dump_trace)
168 		return;
169 
170 	print_binary(raw_event, event->header.size, 16,
171 		     trace_event_printer, event);
172 }
173 
174 static struct debug_variable {
175 	const char *name;
176 	int *ptr;
177 } debug_variables[] = {
178 	{ .name = "verbose",		.ptr = &verbose },
179 	{ .name = "ordered-events",	.ptr = &debug_ordered_events},
180 	{ .name = "stderr",		.ptr = &redirect_to_stderr},
181 	{ .name = "data-convert",	.ptr = &debug_data_convert },
182 	{ .name = NULL, }
183 };
184 
185 int perf_debug_option(const char *str)
186 {
187 	struct debug_variable *var = &debug_variables[0];
188 	char *vstr, *s = strdup(str);
189 	int v = 1;
190 
191 	vstr = strchr(s, '=');
192 	if (vstr)
193 		*vstr++ = 0;
194 
195 	while (var->name) {
196 		if (!strcmp(s, var->name))
197 			break;
198 		var++;
199 	}
200 
201 	if (!var->name) {
202 		pr_err("Unknown debug variable name '%s'\n", s);
203 		free(s);
204 		return -1;
205 	}
206 
207 	if (vstr) {
208 		v = atoi(vstr);
209 		/*
210 		 * Allow only values in range (0, 10),
211 		 * otherwise set 0.
212 		 */
213 		v = (v < 0) || (v > 10) ? 0 : v;
214 	}
215 
216 	if (quiet)
217 		v = -1;
218 
219 	*var->ptr = v;
220 	free(s);
221 	return 0;
222 }
223 
224 int perf_quiet_option(void)
225 {
226 	struct debug_variable *var = &debug_variables[0];
227 
228 	/* disable all debug messages */
229 	while (var->name) {
230 		*var->ptr = -1;
231 		var++;
232 	}
233 
234 	quiet = true;
235 	return 0;
236 }
237 
238 #define DEBUG_WRAPPER(__n, __l)				\
239 static int pr_ ## __n ## _wrapper(const char *fmt, ...)	\
240 {							\
241 	va_list args;					\
242 	int ret;					\
243 							\
244 	va_start(args, fmt);				\
245 	ret = veprintf(__l, verbose, fmt, args);	\
246 	va_end(args);					\
247 	return ret;					\
248 }
249 
250 DEBUG_WRAPPER(warning, 0);
251 DEBUG_WRAPPER(debug, 1);
252 
253 void perf_debug_setup(void)
254 {
255 	libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
256 }
257 
258 /* Obtain a backtrace and print it to stdout. */
259 #ifdef HAVE_BACKTRACE_SUPPORT
260 void dump_stack(void)
261 {
262 	void *array[16];
263 	size_t size = backtrace(array, ARRAY_SIZE(array));
264 	char **strings = backtrace_symbols(array, size);
265 	size_t i;
266 
267 	printf("Obtained %zd stack frames.\n", size);
268 
269 	for (i = 0; i < size; i++)
270 		printf("%s\n", strings[i]);
271 
272 	free(strings);
273 }
274 #else
275 void dump_stack(void) {}
276 #endif
277 
278 void sighandler_dump_stack(int sig)
279 {
280 	psignal(sig, "perf");
281 	dump_stack();
282 	signal(sig, SIG_DFL);
283 	raise(sig);
284 }
285