xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/powerpc/pmu/ebb/trace.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2014, Michael Ellerman, IBM Corp.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <errno.h>
7*4882a593Smuzhiyun #include <stdio.h>
8*4882a593Smuzhiyun #include <stdlib.h>
9*4882a593Smuzhiyun #include <string.h>
10*4882a593Smuzhiyun #include <sys/mman.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "trace.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun 
trace_buffer_allocate(u64 size)15*4882a593Smuzhiyun struct trace_buffer *trace_buffer_allocate(u64 size)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	struct trace_buffer *tb;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 	if (size < sizeof(*tb)) {
20*4882a593Smuzhiyun 		fprintf(stderr, "Error: trace buffer too small\n");
21*4882a593Smuzhiyun 		return NULL;
22*4882a593Smuzhiyun 	}
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun 	tb = mmap(NULL, size, PROT_READ | PROT_WRITE,
25*4882a593Smuzhiyun 		  MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
26*4882a593Smuzhiyun 	if (tb == MAP_FAILED) {
27*4882a593Smuzhiyun 		perror("mmap");
28*4882a593Smuzhiyun 		return NULL;
29*4882a593Smuzhiyun 	}
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	tb->size = size;
32*4882a593Smuzhiyun 	tb->tail = tb->data;
33*4882a593Smuzhiyun 	tb->overflow = false;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	return tb;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun 
trace_check_bounds(struct trace_buffer * tb,void * p)38*4882a593Smuzhiyun static bool trace_check_bounds(struct trace_buffer *tb, void *p)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	return p < ((void *)tb + tb->size);
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun 
trace_check_alloc(struct trace_buffer * tb,void * p)43*4882a593Smuzhiyun static bool trace_check_alloc(struct trace_buffer *tb, void *p)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	/*
46*4882a593Smuzhiyun 	 * If we ever overflowed don't allow any more input. This prevents us
47*4882a593Smuzhiyun 	 * from dropping a large item and then later logging a small one. The
48*4882a593Smuzhiyun 	 * buffer should just stop when overflow happened, not be patchy. If
49*4882a593Smuzhiyun 	 * you're overflowing, make your buffer bigger.
50*4882a593Smuzhiyun 	 */
51*4882a593Smuzhiyun 	if (tb->overflow)
52*4882a593Smuzhiyun 		return false;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	if (!trace_check_bounds(tb, p)) {
55*4882a593Smuzhiyun 		tb->overflow = true;
56*4882a593Smuzhiyun 		return false;
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	return true;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
trace_alloc(struct trace_buffer * tb,int bytes)62*4882a593Smuzhiyun static void *trace_alloc(struct trace_buffer *tb, int bytes)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	void *p, *newtail;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	p = tb->tail;
67*4882a593Smuzhiyun 	newtail = tb->tail + bytes;
68*4882a593Smuzhiyun 	if (!trace_check_alloc(tb, newtail))
69*4882a593Smuzhiyun 		return NULL;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	tb->tail = newtail;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	return p;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
trace_alloc_entry(struct trace_buffer * tb,int payload_size)76*4882a593Smuzhiyun static struct trace_entry *trace_alloc_entry(struct trace_buffer *tb, int payload_size)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	struct trace_entry *e;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	e = trace_alloc(tb, sizeof(*e) + payload_size);
81*4882a593Smuzhiyun 	if (e)
82*4882a593Smuzhiyun 		e->length = payload_size;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	return e;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
trace_log_reg(struct trace_buffer * tb,u64 reg,u64 value)87*4882a593Smuzhiyun int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	struct trace_entry *e;
90*4882a593Smuzhiyun 	u64 *p;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	e = trace_alloc_entry(tb, sizeof(reg) + sizeof(value));
93*4882a593Smuzhiyun 	if (!e)
94*4882a593Smuzhiyun 		return -ENOSPC;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	e->type = TRACE_TYPE_REG;
97*4882a593Smuzhiyun 	p = (u64 *)e->data;
98*4882a593Smuzhiyun 	*p++ = reg;
99*4882a593Smuzhiyun 	*p++ = value;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	return 0;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun 
trace_log_counter(struct trace_buffer * tb,u64 value)104*4882a593Smuzhiyun int trace_log_counter(struct trace_buffer *tb, u64 value)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun 	struct trace_entry *e;
107*4882a593Smuzhiyun 	u64 *p;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	e = trace_alloc_entry(tb, sizeof(value));
110*4882a593Smuzhiyun 	if (!e)
111*4882a593Smuzhiyun 		return -ENOSPC;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	e->type = TRACE_TYPE_COUNTER;
114*4882a593Smuzhiyun 	p = (u64 *)e->data;
115*4882a593Smuzhiyun 	*p++ = value;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	return 0;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
trace_log_string(struct trace_buffer * tb,char * str)120*4882a593Smuzhiyun int trace_log_string(struct trace_buffer *tb, char *str)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	struct trace_entry *e;
123*4882a593Smuzhiyun 	char *p;
124*4882a593Smuzhiyun 	int len;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	len = strlen(str);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/* We NULL terminate to make printing easier */
129*4882a593Smuzhiyun 	e = trace_alloc_entry(tb, len + 1);
130*4882a593Smuzhiyun 	if (!e)
131*4882a593Smuzhiyun 		return -ENOSPC;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	e->type = TRACE_TYPE_STRING;
134*4882a593Smuzhiyun 	p = (char *)e->data;
135*4882a593Smuzhiyun 	memcpy(p, str, len);
136*4882a593Smuzhiyun 	p += len;
137*4882a593Smuzhiyun 	*p = '\0';
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	return 0;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
trace_log_indent(struct trace_buffer * tb)142*4882a593Smuzhiyun int trace_log_indent(struct trace_buffer *tb)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	struct trace_entry *e;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	e = trace_alloc_entry(tb, 0);
147*4882a593Smuzhiyun 	if (!e)
148*4882a593Smuzhiyun 		return -ENOSPC;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	e->type = TRACE_TYPE_INDENT;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	return 0;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
trace_log_outdent(struct trace_buffer * tb)155*4882a593Smuzhiyun int trace_log_outdent(struct trace_buffer *tb)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct trace_entry *e;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	e = trace_alloc_entry(tb, 0);
160*4882a593Smuzhiyun 	if (!e)
161*4882a593Smuzhiyun 		return -ENOSPC;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	e->type = TRACE_TYPE_OUTDENT;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	return 0;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
trace_print_header(int seq,int prefix)168*4882a593Smuzhiyun static void trace_print_header(int seq, int prefix)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	printf("%*s[%d]: ", prefix, "", seq);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
trace_decode_reg(int reg)173*4882a593Smuzhiyun static char *trace_decode_reg(int reg)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	switch (reg) {
176*4882a593Smuzhiyun 		case 769: return "SPRN_MMCR2"; break;
177*4882a593Smuzhiyun 		case 770: return "SPRN_MMCRA"; break;
178*4882a593Smuzhiyun 		case 779: return "SPRN_MMCR0"; break;
179*4882a593Smuzhiyun 		case 804: return "SPRN_EBBHR"; break;
180*4882a593Smuzhiyun 		case 805: return "SPRN_EBBRR"; break;
181*4882a593Smuzhiyun 		case 806: return "SPRN_BESCR"; break;
182*4882a593Smuzhiyun 		case 800: return "SPRN_BESCRS"; break;
183*4882a593Smuzhiyun 		case 801: return "SPRN_BESCRSU"; break;
184*4882a593Smuzhiyun 		case 802: return "SPRN_BESCRR"; break;
185*4882a593Smuzhiyun 		case 803: return "SPRN_BESCRRU"; break;
186*4882a593Smuzhiyun 		case 771: return "SPRN_PMC1"; break;
187*4882a593Smuzhiyun 		case 772: return "SPRN_PMC2"; break;
188*4882a593Smuzhiyun 		case 773: return "SPRN_PMC3"; break;
189*4882a593Smuzhiyun 		case 774: return "SPRN_PMC4"; break;
190*4882a593Smuzhiyun 		case 775: return "SPRN_PMC5"; break;
191*4882a593Smuzhiyun 		case 776: return "SPRN_PMC6"; break;
192*4882a593Smuzhiyun 		case 780: return "SPRN_SIAR"; break;
193*4882a593Smuzhiyun 		case 781: return "SPRN_SDAR"; break;
194*4882a593Smuzhiyun 		case 768: return "SPRN_SIER"; break;
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return NULL;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
trace_print_reg(struct trace_entry * e)200*4882a593Smuzhiyun static void trace_print_reg(struct trace_entry *e)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	u64 *p, *reg, *value;
203*4882a593Smuzhiyun 	char *name;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	p = (u64 *)e->data;
206*4882a593Smuzhiyun 	reg = p++;
207*4882a593Smuzhiyun 	value = p;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	name = trace_decode_reg(*reg);
210*4882a593Smuzhiyun 	if (name)
211*4882a593Smuzhiyun 		printf("register %-10s = 0x%016llx\n", name, *value);
212*4882a593Smuzhiyun 	else
213*4882a593Smuzhiyun 		printf("register %lld = 0x%016llx\n", *reg, *value);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
trace_print_counter(struct trace_entry * e)216*4882a593Smuzhiyun static void trace_print_counter(struct trace_entry *e)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	u64 *value;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	value = (u64 *)e->data;
221*4882a593Smuzhiyun 	printf("counter = %lld\n", *value);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
trace_print_string(struct trace_entry * e)224*4882a593Smuzhiyun static void trace_print_string(struct trace_entry *e)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	char *str;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	str = (char *)e->data;
229*4882a593Smuzhiyun 	puts(str);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun #define BASE_PREFIX	2
233*4882a593Smuzhiyun #define PREFIX_DELTA	8
234*4882a593Smuzhiyun 
trace_print_entry(struct trace_entry * e,int seq,int * prefix)235*4882a593Smuzhiyun static void trace_print_entry(struct trace_entry *e, int seq, int *prefix)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun 	switch (e->type) {
238*4882a593Smuzhiyun 	case TRACE_TYPE_REG:
239*4882a593Smuzhiyun 		trace_print_header(seq, *prefix);
240*4882a593Smuzhiyun 		trace_print_reg(e);
241*4882a593Smuzhiyun 		break;
242*4882a593Smuzhiyun 	case TRACE_TYPE_COUNTER:
243*4882a593Smuzhiyun 		trace_print_header(seq, *prefix);
244*4882a593Smuzhiyun 		trace_print_counter(e);
245*4882a593Smuzhiyun 		break;
246*4882a593Smuzhiyun 	case TRACE_TYPE_STRING:
247*4882a593Smuzhiyun 		trace_print_header(seq, *prefix);
248*4882a593Smuzhiyun 		trace_print_string(e);
249*4882a593Smuzhiyun 		break;
250*4882a593Smuzhiyun 	case TRACE_TYPE_INDENT:
251*4882a593Smuzhiyun 		trace_print_header(seq, *prefix);
252*4882a593Smuzhiyun 		puts("{");
253*4882a593Smuzhiyun 		*prefix += PREFIX_DELTA;
254*4882a593Smuzhiyun 		break;
255*4882a593Smuzhiyun 	case TRACE_TYPE_OUTDENT:
256*4882a593Smuzhiyun 		*prefix -= PREFIX_DELTA;
257*4882a593Smuzhiyun 		if (*prefix < BASE_PREFIX)
258*4882a593Smuzhiyun 			*prefix = BASE_PREFIX;
259*4882a593Smuzhiyun 		trace_print_header(seq, *prefix);
260*4882a593Smuzhiyun 		puts("}");
261*4882a593Smuzhiyun 		break;
262*4882a593Smuzhiyun 	default:
263*4882a593Smuzhiyun 		trace_print_header(seq, *prefix);
264*4882a593Smuzhiyun 		printf("entry @ %p type %d\n", e, e->type);
265*4882a593Smuzhiyun 		break;
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
trace_buffer_print(struct trace_buffer * tb)269*4882a593Smuzhiyun void trace_buffer_print(struct trace_buffer *tb)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	struct trace_entry *e;
272*4882a593Smuzhiyun 	int i, prefix;
273*4882a593Smuzhiyun 	void *p;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	printf("Trace buffer dump:\n");
276*4882a593Smuzhiyun 	printf("  address  %p \n", tb);
277*4882a593Smuzhiyun 	printf("  tail     %p\n", tb->tail);
278*4882a593Smuzhiyun 	printf("  size     %llu\n", tb->size);
279*4882a593Smuzhiyun 	printf("  overflow %s\n", tb->overflow ? "TRUE" : "false");
280*4882a593Smuzhiyun 	printf("  Content:\n");
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	p = tb->data;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	i = 0;
285*4882a593Smuzhiyun 	prefix = BASE_PREFIX;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	while (trace_check_bounds(tb, p) && p < tb->tail) {
288*4882a593Smuzhiyun 		e = p;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 		trace_print_entry(e, i, &prefix);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 		i++;
293*4882a593Smuzhiyun 		p = (void *)e + sizeof(*e) + e->length;
294*4882a593Smuzhiyun 	}
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
trace_print_location(struct trace_buffer * tb)297*4882a593Smuzhiyun void trace_print_location(struct trace_buffer *tb)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	printf("Trace buffer 0x%llx bytes @ %p\n", tb->size, tb);
300*4882a593Smuzhiyun }
301