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