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