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