xref: /OK3568_Linux_fs/kernel/tools/lib/traceevent/kbuffer-parse.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: LGPL-2.1
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include <stdio.h>
7*4882a593Smuzhiyun #include <stdlib.h>
8*4882a593Smuzhiyun #include <string.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "kbuffer.h"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #define MISSING_EVENTS (1UL << 31)
13*4882a593Smuzhiyun #define MISSING_STORED (1UL << 30)
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #define COMMIT_MASK ((1 << 27) - 1)
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun enum {
18*4882a593Smuzhiyun 	KBUFFER_FL_HOST_BIG_ENDIAN	= (1<<0),
19*4882a593Smuzhiyun 	KBUFFER_FL_BIG_ENDIAN		= (1<<1),
20*4882a593Smuzhiyun 	KBUFFER_FL_LONG_8		= (1<<2),
21*4882a593Smuzhiyun 	KBUFFER_FL_OLD_FORMAT		= (1<<3),
22*4882a593Smuzhiyun };
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define ENDIAN_MASK (KBUFFER_FL_HOST_BIG_ENDIAN | KBUFFER_FL_BIG_ENDIAN)
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /** kbuffer
27*4882a593Smuzhiyun  * @timestamp		- timestamp of current event
28*4882a593Smuzhiyun  * @lost_events		- # of lost events between this subbuffer and previous
29*4882a593Smuzhiyun  * @flags		- special flags of the kbuffer
30*4882a593Smuzhiyun  * @subbuffer		- pointer to the sub-buffer page
31*4882a593Smuzhiyun  * @data		- pointer to the start of data on the sub-buffer page
32*4882a593Smuzhiyun  * @index		- index from @data to the @curr event data
33*4882a593Smuzhiyun  * @curr		- offset from @data to the start of current event
34*4882a593Smuzhiyun  *			   (includes metadata)
35*4882a593Smuzhiyun  * @next		- offset from @data to the start of next event
36*4882a593Smuzhiyun  * @size		- The size of data on @data
37*4882a593Smuzhiyun  * @start		- The offset from @subbuffer where @data lives
38*4882a593Smuzhiyun  *
39*4882a593Smuzhiyun  * @read_4		- Function to read 4 raw bytes (may swap)
40*4882a593Smuzhiyun  * @read_8		- Function to read 8 raw bytes (may swap)
41*4882a593Smuzhiyun  * @read_long		- Function to read a long word (4 or 8 bytes with needed swap)
42*4882a593Smuzhiyun  */
43*4882a593Smuzhiyun struct kbuffer {
44*4882a593Smuzhiyun 	unsigned long long 	timestamp;
45*4882a593Smuzhiyun 	long long		lost_events;
46*4882a593Smuzhiyun 	unsigned long		flags;
47*4882a593Smuzhiyun 	void			*subbuffer;
48*4882a593Smuzhiyun 	void			*data;
49*4882a593Smuzhiyun 	unsigned int		index;
50*4882a593Smuzhiyun 	unsigned int		curr;
51*4882a593Smuzhiyun 	unsigned int		next;
52*4882a593Smuzhiyun 	unsigned int		size;
53*4882a593Smuzhiyun 	unsigned int		start;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	unsigned int (*read_4)(void *ptr);
56*4882a593Smuzhiyun 	unsigned long long (*read_8)(void *ptr);
57*4882a593Smuzhiyun 	unsigned long long (*read_long)(struct kbuffer *kbuf, void *ptr);
58*4882a593Smuzhiyun 	int (*next_event)(struct kbuffer *kbuf);
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun 
zmalloc(size_t size)61*4882a593Smuzhiyun static void *zmalloc(size_t size)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	return calloc(1, size);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
host_is_bigendian(void)66*4882a593Smuzhiyun static int host_is_bigendian(void)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
69*4882a593Smuzhiyun 	unsigned int *ptr;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	ptr = (unsigned int *)str;
72*4882a593Smuzhiyun 	return *ptr == 0x01020304;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
do_swap(struct kbuffer * kbuf)75*4882a593Smuzhiyun static int do_swap(struct kbuffer *kbuf)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) &
78*4882a593Smuzhiyun 		ENDIAN_MASK;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
__read_8(void * ptr)81*4882a593Smuzhiyun static unsigned long long __read_8(void *ptr)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	unsigned long long data = *(unsigned long long *)ptr;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	return data;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
__read_8_sw(void * ptr)88*4882a593Smuzhiyun static unsigned long long __read_8_sw(void *ptr)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun 	unsigned long long data = *(unsigned long long *)ptr;
91*4882a593Smuzhiyun 	unsigned long long swap;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	swap = ((data & 0xffULL) << 56) |
94*4882a593Smuzhiyun 		((data & (0xffULL << 8)) << 40) |
95*4882a593Smuzhiyun 		((data & (0xffULL << 16)) << 24) |
96*4882a593Smuzhiyun 		((data & (0xffULL << 24)) << 8) |
97*4882a593Smuzhiyun 		((data & (0xffULL << 32)) >> 8) |
98*4882a593Smuzhiyun 		((data & (0xffULL << 40)) >> 24) |
99*4882a593Smuzhiyun 		((data & (0xffULL << 48)) >> 40) |
100*4882a593Smuzhiyun 		((data & (0xffULL << 56)) >> 56);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	return swap;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
__read_4(void * ptr)105*4882a593Smuzhiyun static unsigned int __read_4(void *ptr)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	unsigned int data = *(unsigned int *)ptr;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return data;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
__read_4_sw(void * ptr)112*4882a593Smuzhiyun static unsigned int __read_4_sw(void *ptr)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	unsigned int data = *(unsigned int *)ptr;
115*4882a593Smuzhiyun 	unsigned int swap;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	swap = ((data & 0xffULL) << 24) |
118*4882a593Smuzhiyun 		((data & (0xffULL << 8)) << 8) |
119*4882a593Smuzhiyun 		((data & (0xffULL << 16)) >> 8) |
120*4882a593Smuzhiyun 		((data & (0xffULL << 24)) >> 24);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return swap;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
read_8(struct kbuffer * kbuf,void * ptr)125*4882a593Smuzhiyun static unsigned long long read_8(struct kbuffer *kbuf, void *ptr)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	return kbuf->read_8(ptr);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
read_4(struct kbuffer * kbuf,void * ptr)130*4882a593Smuzhiyun static unsigned int read_4(struct kbuffer *kbuf, void *ptr)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	return kbuf->read_4(ptr);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
__read_long_8(struct kbuffer * kbuf,void * ptr)135*4882a593Smuzhiyun static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	return kbuf->read_8(ptr);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
__read_long_4(struct kbuffer * kbuf,void * ptr)140*4882a593Smuzhiyun static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	return kbuf->read_4(ptr);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
read_long(struct kbuffer * kbuf,void * ptr)145*4882a593Smuzhiyun static unsigned long long read_long(struct kbuffer *kbuf, void *ptr)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	return kbuf->read_long(kbuf, ptr);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
calc_index(struct kbuffer * kbuf,void * ptr)150*4882a593Smuzhiyun static int calc_index(struct kbuffer *kbuf, void *ptr)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	return (unsigned long)ptr - (unsigned long)kbuf->data;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun static int __next_event(struct kbuffer *kbuf);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun /**
158*4882a593Smuzhiyun  * kbuffer_alloc - allocat a new kbuffer
159*4882a593Smuzhiyun  * @size;	enum to denote size of word
160*4882a593Smuzhiyun  * @endian:	enum to denote endianness
161*4882a593Smuzhiyun  *
162*4882a593Smuzhiyun  * Allocates and returns a new kbuffer.
163*4882a593Smuzhiyun  */
164*4882a593Smuzhiyun struct kbuffer *
kbuffer_alloc(enum kbuffer_long_size size,enum kbuffer_endian endian)165*4882a593Smuzhiyun kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	struct kbuffer *kbuf;
168*4882a593Smuzhiyun 	int flags = 0;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	switch (size) {
171*4882a593Smuzhiyun 	case KBUFFER_LSIZE_4:
172*4882a593Smuzhiyun 		break;
173*4882a593Smuzhiyun 	case KBUFFER_LSIZE_8:
174*4882a593Smuzhiyun 		flags |= KBUFFER_FL_LONG_8;
175*4882a593Smuzhiyun 		break;
176*4882a593Smuzhiyun 	default:
177*4882a593Smuzhiyun 		return NULL;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	switch (endian) {
181*4882a593Smuzhiyun 	case KBUFFER_ENDIAN_LITTLE:
182*4882a593Smuzhiyun 		break;
183*4882a593Smuzhiyun 	case KBUFFER_ENDIAN_BIG:
184*4882a593Smuzhiyun 		flags |= KBUFFER_FL_BIG_ENDIAN;
185*4882a593Smuzhiyun 		break;
186*4882a593Smuzhiyun 	default:
187*4882a593Smuzhiyun 		return NULL;
188*4882a593Smuzhiyun 	}
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	kbuf = zmalloc(sizeof(*kbuf));
191*4882a593Smuzhiyun 	if (!kbuf)
192*4882a593Smuzhiyun 		return NULL;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	kbuf->flags = flags;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (host_is_bigendian())
197*4882a593Smuzhiyun 		kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (do_swap(kbuf)) {
200*4882a593Smuzhiyun 		kbuf->read_8 = __read_8_sw;
201*4882a593Smuzhiyun 		kbuf->read_4 = __read_4_sw;
202*4882a593Smuzhiyun 	} else {
203*4882a593Smuzhiyun 		kbuf->read_8 = __read_8;
204*4882a593Smuzhiyun 		kbuf->read_4 = __read_4;
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	if (kbuf->flags & KBUFFER_FL_LONG_8)
208*4882a593Smuzhiyun 		kbuf->read_long = __read_long_8;
209*4882a593Smuzhiyun 	else
210*4882a593Smuzhiyun 		kbuf->read_long = __read_long_4;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	/* May be changed by kbuffer_set_old_format() */
213*4882a593Smuzhiyun 	kbuf->next_event = __next_event;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	return kbuf;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun /** kbuffer_free - free an allocated kbuffer
219*4882a593Smuzhiyun  * @kbuf:	The kbuffer to free
220*4882a593Smuzhiyun  *
221*4882a593Smuzhiyun  * Can take NULL as a parameter.
222*4882a593Smuzhiyun  */
kbuffer_free(struct kbuffer * kbuf)223*4882a593Smuzhiyun void kbuffer_free(struct kbuffer *kbuf)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	free(kbuf);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
type4host(struct kbuffer * kbuf,unsigned int type_len_ts)228*4882a593Smuzhiyun static unsigned int type4host(struct kbuffer *kbuf,
229*4882a593Smuzhiyun 			      unsigned int type_len_ts)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
232*4882a593Smuzhiyun 		return (type_len_ts >> 29) & 3;
233*4882a593Smuzhiyun 	else
234*4882a593Smuzhiyun 		return type_len_ts & 3;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
len4host(struct kbuffer * kbuf,unsigned int type_len_ts)237*4882a593Smuzhiyun static unsigned int len4host(struct kbuffer *kbuf,
238*4882a593Smuzhiyun 			     unsigned int type_len_ts)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
241*4882a593Smuzhiyun 		return (type_len_ts >> 27) & 7;
242*4882a593Smuzhiyun 	else
243*4882a593Smuzhiyun 		return (type_len_ts >> 2) & 7;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
type_len4host(struct kbuffer * kbuf,unsigned int type_len_ts)246*4882a593Smuzhiyun static unsigned int type_len4host(struct kbuffer *kbuf,
247*4882a593Smuzhiyun 				  unsigned int type_len_ts)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
250*4882a593Smuzhiyun 		return (type_len_ts >> 27) & ((1 << 5) - 1);
251*4882a593Smuzhiyun 	else
252*4882a593Smuzhiyun 		return type_len_ts & ((1 << 5) - 1);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
ts4host(struct kbuffer * kbuf,unsigned int type_len_ts)255*4882a593Smuzhiyun static unsigned int ts4host(struct kbuffer *kbuf,
256*4882a593Smuzhiyun 			    unsigned int type_len_ts)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN)
259*4882a593Smuzhiyun 		return type_len_ts & ((1 << 27) - 1);
260*4882a593Smuzhiyun 	else
261*4882a593Smuzhiyun 		return type_len_ts >> 5;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun /*
265*4882a593Smuzhiyun  * Linux 2.6.30 and earlier (not much ealier) had a different
266*4882a593Smuzhiyun  * ring buffer format. It should be obsolete, but we handle it anyway.
267*4882a593Smuzhiyun  */
268*4882a593Smuzhiyun enum old_ring_buffer_type {
269*4882a593Smuzhiyun 	OLD_RINGBUF_TYPE_PADDING,
270*4882a593Smuzhiyun 	OLD_RINGBUF_TYPE_TIME_EXTEND,
271*4882a593Smuzhiyun 	OLD_RINGBUF_TYPE_TIME_STAMP,
272*4882a593Smuzhiyun 	OLD_RINGBUF_TYPE_DATA,
273*4882a593Smuzhiyun };
274*4882a593Smuzhiyun 
old_update_pointers(struct kbuffer * kbuf)275*4882a593Smuzhiyun static unsigned int old_update_pointers(struct kbuffer *kbuf)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	unsigned long long extend;
278*4882a593Smuzhiyun 	unsigned int type_len_ts;
279*4882a593Smuzhiyun 	unsigned int type;
280*4882a593Smuzhiyun 	unsigned int len;
281*4882a593Smuzhiyun 	unsigned int delta;
282*4882a593Smuzhiyun 	unsigned int length;
283*4882a593Smuzhiyun 	void *ptr = kbuf->data + kbuf->curr;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	type_len_ts = read_4(kbuf, ptr);
286*4882a593Smuzhiyun 	ptr += 4;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	type = type4host(kbuf, type_len_ts);
289*4882a593Smuzhiyun 	len = len4host(kbuf, type_len_ts);
290*4882a593Smuzhiyun 	delta = ts4host(kbuf, type_len_ts);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	switch (type) {
293*4882a593Smuzhiyun 	case OLD_RINGBUF_TYPE_PADDING:
294*4882a593Smuzhiyun 		kbuf->next = kbuf->size;
295*4882a593Smuzhiyun 		return 0;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	case OLD_RINGBUF_TYPE_TIME_EXTEND:
298*4882a593Smuzhiyun 		extend = read_4(kbuf, ptr);
299*4882a593Smuzhiyun 		extend <<= TS_SHIFT;
300*4882a593Smuzhiyun 		extend += delta;
301*4882a593Smuzhiyun 		delta = extend;
302*4882a593Smuzhiyun 		ptr += 4;
303*4882a593Smuzhiyun 		length = 0;
304*4882a593Smuzhiyun 		break;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	case OLD_RINGBUF_TYPE_TIME_STAMP:
307*4882a593Smuzhiyun 		/* should never happen! */
308*4882a593Smuzhiyun 		kbuf->curr = kbuf->size;
309*4882a593Smuzhiyun 		kbuf->next = kbuf->size;
310*4882a593Smuzhiyun 		kbuf->index = kbuf->size;
311*4882a593Smuzhiyun 		return -1;
312*4882a593Smuzhiyun 	default:
313*4882a593Smuzhiyun 		if (len)
314*4882a593Smuzhiyun 			length = len * 4;
315*4882a593Smuzhiyun 		else {
316*4882a593Smuzhiyun 			length = read_4(kbuf, ptr);
317*4882a593Smuzhiyun 			length -= 4;
318*4882a593Smuzhiyun 			ptr += 4;
319*4882a593Smuzhiyun 		}
320*4882a593Smuzhiyun 		break;
321*4882a593Smuzhiyun 	}
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	kbuf->timestamp += delta;
324*4882a593Smuzhiyun 	kbuf->index = calc_index(kbuf, ptr);
325*4882a593Smuzhiyun 	kbuf->next = kbuf->index + length;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	return type;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
__old_next_event(struct kbuffer * kbuf)330*4882a593Smuzhiyun static int __old_next_event(struct kbuffer *kbuf)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	int type;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	do {
335*4882a593Smuzhiyun 		kbuf->curr = kbuf->next;
336*4882a593Smuzhiyun 		if (kbuf->next >= kbuf->size)
337*4882a593Smuzhiyun 			return -1;
338*4882a593Smuzhiyun 		type = old_update_pointers(kbuf);
339*4882a593Smuzhiyun 	} while (type == OLD_RINGBUF_TYPE_TIME_EXTEND || type == OLD_RINGBUF_TYPE_PADDING);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	return 0;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun static unsigned int
translate_data(struct kbuffer * kbuf,void * data,void ** rptr,unsigned long long * delta,int * length)345*4882a593Smuzhiyun translate_data(struct kbuffer *kbuf, void *data, void **rptr,
346*4882a593Smuzhiyun 	       unsigned long long *delta, int *length)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun 	unsigned long long extend;
349*4882a593Smuzhiyun 	unsigned int type_len_ts;
350*4882a593Smuzhiyun 	unsigned int type_len;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	type_len_ts = read_4(kbuf, data);
353*4882a593Smuzhiyun 	data += 4;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	type_len = type_len4host(kbuf, type_len_ts);
356*4882a593Smuzhiyun 	*delta = ts4host(kbuf, type_len_ts);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	switch (type_len) {
359*4882a593Smuzhiyun 	case KBUFFER_TYPE_PADDING:
360*4882a593Smuzhiyun 		*length = read_4(kbuf, data);
361*4882a593Smuzhiyun 		break;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	case KBUFFER_TYPE_TIME_EXTEND:
364*4882a593Smuzhiyun 	case KBUFFER_TYPE_TIME_STAMP:
365*4882a593Smuzhiyun 		extend = read_4(kbuf, data);
366*4882a593Smuzhiyun 		data += 4;
367*4882a593Smuzhiyun 		extend <<= TS_SHIFT;
368*4882a593Smuzhiyun 		extend += *delta;
369*4882a593Smuzhiyun 		*delta = extend;
370*4882a593Smuzhiyun 		*length = 0;
371*4882a593Smuzhiyun 		break;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	case 0:
374*4882a593Smuzhiyun 		*length = read_4(kbuf, data) - 4;
375*4882a593Smuzhiyun 		*length = (*length + 3) & ~3;
376*4882a593Smuzhiyun 		data += 4;
377*4882a593Smuzhiyun 		break;
378*4882a593Smuzhiyun 	default:
379*4882a593Smuzhiyun 		*length = type_len * 4;
380*4882a593Smuzhiyun 		break;
381*4882a593Smuzhiyun 	}
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	*rptr = data;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	return type_len;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
update_pointers(struct kbuffer * kbuf)388*4882a593Smuzhiyun static unsigned int update_pointers(struct kbuffer *kbuf)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	unsigned long long delta;
391*4882a593Smuzhiyun 	unsigned int type_len;
392*4882a593Smuzhiyun 	int length;
393*4882a593Smuzhiyun 	void *ptr = kbuf->data + kbuf->curr;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	type_len = translate_data(kbuf, ptr, &ptr, &delta, &length);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if (type_len == KBUFFER_TYPE_TIME_STAMP)
398*4882a593Smuzhiyun 		kbuf->timestamp = delta;
399*4882a593Smuzhiyun 	else
400*4882a593Smuzhiyun 		kbuf->timestamp += delta;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	kbuf->index = calc_index(kbuf, ptr);
403*4882a593Smuzhiyun 	kbuf->next = kbuf->index + length;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	return type_len;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun /**
409*4882a593Smuzhiyun  * kbuffer_translate_data - read raw data to get a record
410*4882a593Smuzhiyun  * @swap:	Set to 1 if bytes in words need to be swapped when read
411*4882a593Smuzhiyun  * @data:	The raw data to read
412*4882a593Smuzhiyun  * @size:	Address to store the size of the event data.
413*4882a593Smuzhiyun  *
414*4882a593Smuzhiyun  * Returns a pointer to the event data. To determine the entire
415*4882a593Smuzhiyun  * record size (record metadata + data) just add the difference between
416*4882a593Smuzhiyun  * @data and the returned value to @size.
417*4882a593Smuzhiyun  */
kbuffer_translate_data(int swap,void * data,unsigned int * size)418*4882a593Smuzhiyun void *kbuffer_translate_data(int swap, void *data, unsigned int *size)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	unsigned long long delta;
421*4882a593Smuzhiyun 	struct kbuffer kbuf;
422*4882a593Smuzhiyun 	int type_len;
423*4882a593Smuzhiyun 	int length;
424*4882a593Smuzhiyun 	void *ptr;
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (swap) {
427*4882a593Smuzhiyun 		kbuf.read_8 = __read_8_sw;
428*4882a593Smuzhiyun 		kbuf.read_4 = __read_4_sw;
429*4882a593Smuzhiyun 		kbuf.flags = host_is_bigendian() ? 0 : KBUFFER_FL_BIG_ENDIAN;
430*4882a593Smuzhiyun 	} else {
431*4882a593Smuzhiyun 		kbuf.read_8 = __read_8;
432*4882a593Smuzhiyun 		kbuf.read_4 = __read_4;
433*4882a593Smuzhiyun 		kbuf.flags = host_is_bigendian() ? KBUFFER_FL_BIG_ENDIAN: 0;
434*4882a593Smuzhiyun 	}
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	type_len = translate_data(&kbuf, data, &ptr, &delta, &length);
437*4882a593Smuzhiyun 	switch (type_len) {
438*4882a593Smuzhiyun 	case KBUFFER_TYPE_PADDING:
439*4882a593Smuzhiyun 	case KBUFFER_TYPE_TIME_EXTEND:
440*4882a593Smuzhiyun 	case KBUFFER_TYPE_TIME_STAMP:
441*4882a593Smuzhiyun 		return NULL;
442*4882a593Smuzhiyun 	}
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	*size = length;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	return ptr;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
__next_event(struct kbuffer * kbuf)449*4882a593Smuzhiyun static int __next_event(struct kbuffer *kbuf)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun 	int type;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	do {
454*4882a593Smuzhiyun 		kbuf->curr = kbuf->next;
455*4882a593Smuzhiyun 		if (kbuf->next >= kbuf->size)
456*4882a593Smuzhiyun 			return -1;
457*4882a593Smuzhiyun 		type = update_pointers(kbuf);
458*4882a593Smuzhiyun 	} while (type == KBUFFER_TYPE_TIME_EXTEND ||
459*4882a593Smuzhiyun 		 type == KBUFFER_TYPE_TIME_STAMP ||
460*4882a593Smuzhiyun 		 type == KBUFFER_TYPE_PADDING);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	return 0;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
next_event(struct kbuffer * kbuf)465*4882a593Smuzhiyun static int next_event(struct kbuffer *kbuf)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun 	return kbuf->next_event(kbuf);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun /**
471*4882a593Smuzhiyun  * kbuffer_next_event - increment the current pointer
472*4882a593Smuzhiyun  * @kbuf:	The kbuffer to read
473*4882a593Smuzhiyun  * @ts:		Address to store the next record's timestamp (may be NULL to ignore)
474*4882a593Smuzhiyun  *
475*4882a593Smuzhiyun  * Increments the pointers into the subbuffer of the kbuffer to point to the
476*4882a593Smuzhiyun  * next event so that the next kbuffer_read_event() will return a
477*4882a593Smuzhiyun  * new event.
478*4882a593Smuzhiyun  *
479*4882a593Smuzhiyun  * Returns the data of the next event if a new event exists on the subbuffer,
480*4882a593Smuzhiyun  * NULL otherwise.
481*4882a593Smuzhiyun  */
kbuffer_next_event(struct kbuffer * kbuf,unsigned long long * ts)482*4882a593Smuzhiyun void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun 	int ret;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (!kbuf || !kbuf->subbuffer)
487*4882a593Smuzhiyun 		return NULL;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	ret = next_event(kbuf);
490*4882a593Smuzhiyun 	if (ret < 0)
491*4882a593Smuzhiyun 		return NULL;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	if (ts)
494*4882a593Smuzhiyun 		*ts = kbuf->timestamp;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	return kbuf->data + kbuf->index;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun /**
500*4882a593Smuzhiyun  * kbuffer_load_subbuffer - load a new subbuffer into the kbuffer
501*4882a593Smuzhiyun  * @kbuf:	The kbuffer to load
502*4882a593Smuzhiyun  * @subbuffer:	The subbuffer to load into @kbuf.
503*4882a593Smuzhiyun  *
504*4882a593Smuzhiyun  * Load a new subbuffer (page) into @kbuf. This will reset all
505*4882a593Smuzhiyun  * the pointers and update the @kbuf timestamp. The next read will
506*4882a593Smuzhiyun  * return the first event on @subbuffer.
507*4882a593Smuzhiyun  *
508*4882a593Smuzhiyun  * Returns 0 on succes, -1 otherwise.
509*4882a593Smuzhiyun  */
kbuffer_load_subbuffer(struct kbuffer * kbuf,void * subbuffer)510*4882a593Smuzhiyun int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	unsigned long long flags;
513*4882a593Smuzhiyun 	void *ptr = subbuffer;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	if (!kbuf || !subbuffer)
516*4882a593Smuzhiyun 		return -1;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	kbuf->subbuffer = subbuffer;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	kbuf->timestamp = read_8(kbuf, ptr);
521*4882a593Smuzhiyun 	ptr += 8;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	kbuf->curr = 0;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	if (kbuf->flags & KBUFFER_FL_LONG_8)
526*4882a593Smuzhiyun 		kbuf->start = 16;
527*4882a593Smuzhiyun 	else
528*4882a593Smuzhiyun 		kbuf->start = 12;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	kbuf->data = subbuffer + kbuf->start;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	flags = read_long(kbuf, ptr);
533*4882a593Smuzhiyun 	kbuf->size = (unsigned int)flags & COMMIT_MASK;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	if (flags & MISSING_EVENTS) {
536*4882a593Smuzhiyun 		if (flags & MISSING_STORED) {
537*4882a593Smuzhiyun 			ptr = kbuf->data + kbuf->size;
538*4882a593Smuzhiyun 			kbuf->lost_events = read_long(kbuf, ptr);
539*4882a593Smuzhiyun 		} else
540*4882a593Smuzhiyun 			kbuf->lost_events = -1;
541*4882a593Smuzhiyun 	} else
542*4882a593Smuzhiyun 		kbuf->lost_events = 0;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	kbuf->index = 0;
545*4882a593Smuzhiyun 	kbuf->next = 0;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	next_event(kbuf);
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	return 0;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun /**
553*4882a593Smuzhiyun  * kbuffer_subbuf_timestamp - read the timestamp from a sub buffer
554*4882a593Smuzhiyun  * @kbuf:      The kbuffer to load
555*4882a593Smuzhiyun  * @subbuf:    The subbuffer to read from.
556*4882a593Smuzhiyun  *
557*4882a593Smuzhiyun  * Return the timestamp from a subbuffer.
558*4882a593Smuzhiyun  */
kbuffer_subbuf_timestamp(struct kbuffer * kbuf,void * subbuf)559*4882a593Smuzhiyun unsigned long long kbuffer_subbuf_timestamp(struct kbuffer *kbuf, void *subbuf)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun 	return kbuf->read_8(subbuf);
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun /**
565*4882a593Smuzhiyun  * kbuffer_ptr_delta - read the delta field from a record
566*4882a593Smuzhiyun  * @kbuf:      The kbuffer to load
567*4882a593Smuzhiyun  * @ptr:       The record in the buffe.
568*4882a593Smuzhiyun  *
569*4882a593Smuzhiyun  * Return the timestamp delta from a record
570*4882a593Smuzhiyun  */
kbuffer_ptr_delta(struct kbuffer * kbuf,void * ptr)571*4882a593Smuzhiyun unsigned int kbuffer_ptr_delta(struct kbuffer *kbuf, void *ptr)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	unsigned int type_len_ts;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	type_len_ts = read_4(kbuf, ptr);
576*4882a593Smuzhiyun 	return ts4host(kbuf, type_len_ts);
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun /**
581*4882a593Smuzhiyun  * kbuffer_read_event - read the next event in the kbuffer subbuffer
582*4882a593Smuzhiyun  * @kbuf:	The kbuffer to read from
583*4882a593Smuzhiyun  * @ts:		The address to store the timestamp of the event (may be NULL to ignore)
584*4882a593Smuzhiyun  *
585*4882a593Smuzhiyun  * Returns a pointer to the data part of the current event.
586*4882a593Smuzhiyun  * NULL if no event is left on the subbuffer.
587*4882a593Smuzhiyun  */
kbuffer_read_event(struct kbuffer * kbuf,unsigned long long * ts)588*4882a593Smuzhiyun void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun 	if (!kbuf || !kbuf->subbuffer)
591*4882a593Smuzhiyun 		return NULL;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	if (kbuf->curr >= kbuf->size)
594*4882a593Smuzhiyun 		return NULL;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	if (ts)
597*4882a593Smuzhiyun 		*ts = kbuf->timestamp;
598*4882a593Smuzhiyun 	return kbuf->data + kbuf->index;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun /**
602*4882a593Smuzhiyun  * kbuffer_timestamp - Return the timestamp of the current event
603*4882a593Smuzhiyun  * @kbuf:	The kbuffer to read from
604*4882a593Smuzhiyun  *
605*4882a593Smuzhiyun  * Returns the timestamp of the current (next) event.
606*4882a593Smuzhiyun  */
kbuffer_timestamp(struct kbuffer * kbuf)607*4882a593Smuzhiyun unsigned long long kbuffer_timestamp(struct kbuffer *kbuf)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	return kbuf->timestamp;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun /**
613*4882a593Smuzhiyun  * kbuffer_read_at_offset - read the event that is at offset
614*4882a593Smuzhiyun  * @kbuf:	The kbuffer to read from
615*4882a593Smuzhiyun  * @offset:	The offset into the subbuffer
616*4882a593Smuzhiyun  * @ts:		The address to store the timestamp of the event (may be NULL to ignore)
617*4882a593Smuzhiyun  *
618*4882a593Smuzhiyun  * The @offset must be an index from the @kbuf subbuffer beginning.
619*4882a593Smuzhiyun  * If @offset is bigger than the stored subbuffer, NULL will be returned.
620*4882a593Smuzhiyun  *
621*4882a593Smuzhiyun  * Returns the data of the record that is at @offset. Note, @offset does
622*4882a593Smuzhiyun  * not need to be the start of the record, the offset just needs to be
623*4882a593Smuzhiyun  * in the record (or beginning of it).
624*4882a593Smuzhiyun  *
625*4882a593Smuzhiyun  * Note, the kbuf timestamp and pointers are updated to the
626*4882a593Smuzhiyun  * returned record. That is, kbuffer_read_event() will return the same
627*4882a593Smuzhiyun  * data and timestamp, and kbuffer_next_event() will increment from
628*4882a593Smuzhiyun  * this record.
629*4882a593Smuzhiyun  */
kbuffer_read_at_offset(struct kbuffer * kbuf,int offset,unsigned long long * ts)630*4882a593Smuzhiyun void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset,
631*4882a593Smuzhiyun 			     unsigned long long *ts)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun 	void *data;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	if (offset < kbuf->start)
636*4882a593Smuzhiyun 		offset = 0;
637*4882a593Smuzhiyun 	else
638*4882a593Smuzhiyun 		offset -= kbuf->start;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	/* Reset the buffer */
641*4882a593Smuzhiyun 	kbuffer_load_subbuffer(kbuf, kbuf->subbuffer);
642*4882a593Smuzhiyun 	data = kbuffer_read_event(kbuf, ts);
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	while (kbuf->curr < offset) {
645*4882a593Smuzhiyun 		data = kbuffer_next_event(kbuf, ts);
646*4882a593Smuzhiyun 		if (!data)
647*4882a593Smuzhiyun 			break;
648*4882a593Smuzhiyun 	}
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	return data;
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun /**
654*4882a593Smuzhiyun  * kbuffer_subbuffer_size - the size of the loaded subbuffer
655*4882a593Smuzhiyun  * @kbuf:	The kbuffer to read from
656*4882a593Smuzhiyun  *
657*4882a593Smuzhiyun  * Returns the size of the subbuffer. Note, this size is
658*4882a593Smuzhiyun  * where the last event resides. The stored subbuffer may actually be
659*4882a593Smuzhiyun  * bigger due to padding and such.
660*4882a593Smuzhiyun  */
kbuffer_subbuffer_size(struct kbuffer * kbuf)661*4882a593Smuzhiyun int kbuffer_subbuffer_size(struct kbuffer *kbuf)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun 	return kbuf->size;
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun /**
667*4882a593Smuzhiyun  * kbuffer_curr_index - Return the index of the record
668*4882a593Smuzhiyun  * @kbuf:	The kbuffer to read from
669*4882a593Smuzhiyun  *
670*4882a593Smuzhiyun  * Returns the index from the start of the data part of
671*4882a593Smuzhiyun  * the subbuffer to the current location. Note this is not
672*4882a593Smuzhiyun  * from the start of the subbuffer. An index of zero will
673*4882a593Smuzhiyun  * point to the first record. Use kbuffer_curr_offset() for
674*4882a593Smuzhiyun  * the actually offset (that can be used by kbuffer_read_at_offset())
675*4882a593Smuzhiyun  */
kbuffer_curr_index(struct kbuffer * kbuf)676*4882a593Smuzhiyun int kbuffer_curr_index(struct kbuffer *kbuf)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun 	return kbuf->curr;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun /**
682*4882a593Smuzhiyun  * kbuffer_curr_offset - Return the offset of the record
683*4882a593Smuzhiyun  * @kbuf:	The kbuffer to read from
684*4882a593Smuzhiyun  *
685*4882a593Smuzhiyun  * Returns the offset from the start of the subbuffer to the
686*4882a593Smuzhiyun  * current location.
687*4882a593Smuzhiyun  */
kbuffer_curr_offset(struct kbuffer * kbuf)688*4882a593Smuzhiyun int kbuffer_curr_offset(struct kbuffer *kbuf)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun 	return kbuf->curr + kbuf->start;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun /**
694*4882a593Smuzhiyun  * kbuffer_event_size - return the size of the event data
695*4882a593Smuzhiyun  * @kbuf:	The kbuffer to read
696*4882a593Smuzhiyun  *
697*4882a593Smuzhiyun  * Returns the size of the event data (the payload not counting
698*4882a593Smuzhiyun  * the meta data of the record) of the current event.
699*4882a593Smuzhiyun  */
kbuffer_event_size(struct kbuffer * kbuf)700*4882a593Smuzhiyun int kbuffer_event_size(struct kbuffer *kbuf)
701*4882a593Smuzhiyun {
702*4882a593Smuzhiyun 	return kbuf->next - kbuf->index;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun /**
706*4882a593Smuzhiyun  * kbuffer_curr_size - return the size of the entire record
707*4882a593Smuzhiyun  * @kbuf:	The kbuffer to read
708*4882a593Smuzhiyun  *
709*4882a593Smuzhiyun  * Returns the size of the entire record (meta data and payload)
710*4882a593Smuzhiyun  * of the current event.
711*4882a593Smuzhiyun  */
kbuffer_curr_size(struct kbuffer * kbuf)712*4882a593Smuzhiyun int kbuffer_curr_size(struct kbuffer *kbuf)
713*4882a593Smuzhiyun {
714*4882a593Smuzhiyun 	return kbuf->next - kbuf->curr;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun /**
718*4882a593Smuzhiyun  * kbuffer_missed_events - return the # of missed events from last event.
719*4882a593Smuzhiyun  * @kbuf: 	The kbuffer to read from
720*4882a593Smuzhiyun  *
721*4882a593Smuzhiyun  * Returns the # of missed events (if recorded) before the current
722*4882a593Smuzhiyun  * event. Note, only events on the beginning of a subbuffer can
723*4882a593Smuzhiyun  * have missed events, all other events within the buffer will be
724*4882a593Smuzhiyun  * zero.
725*4882a593Smuzhiyun  */
kbuffer_missed_events(struct kbuffer * kbuf)726*4882a593Smuzhiyun int kbuffer_missed_events(struct kbuffer *kbuf)
727*4882a593Smuzhiyun {
728*4882a593Smuzhiyun 	/* Only the first event can have missed events */
729*4882a593Smuzhiyun 	if (kbuf->curr)
730*4882a593Smuzhiyun 		return 0;
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	return kbuf->lost_events;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun /**
736*4882a593Smuzhiyun  * kbuffer_set_old_forma - set the kbuffer to use the old format parsing
737*4882a593Smuzhiyun  * @kbuf:	The kbuffer to set
738*4882a593Smuzhiyun  *
739*4882a593Smuzhiyun  * This is obsolete (or should be). The first kernels to use the
740*4882a593Smuzhiyun  * new ring buffer had a slightly different ring buffer format
741*4882a593Smuzhiyun  * (2.6.30 and earlier). It is still somewhat supported by kbuffer,
742*4882a593Smuzhiyun  * but should not be counted on in the future.
743*4882a593Smuzhiyun  */
kbuffer_set_old_format(struct kbuffer * kbuf)744*4882a593Smuzhiyun void kbuffer_set_old_format(struct kbuffer *kbuf)
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun 	kbuf->flags |= KBUFFER_FL_OLD_FORMAT;
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	kbuf->next_event = __old_next_event;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun /**
752*4882a593Smuzhiyun  * kbuffer_start_of_data - return offset of where data starts on subbuffer
753*4882a593Smuzhiyun  * @kbuf:	The kbuffer
754*4882a593Smuzhiyun  *
755*4882a593Smuzhiyun  * Returns the location on the subbuffer where the data starts.
756*4882a593Smuzhiyun  */
kbuffer_start_of_data(struct kbuffer * kbuf)757*4882a593Smuzhiyun int kbuffer_start_of_data(struct kbuffer *kbuf)
758*4882a593Smuzhiyun {
759*4882a593Smuzhiyun 	return kbuf->start;
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun /**
763*4882a593Smuzhiyun  * kbuffer_raw_get - get raw buffer info
764*4882a593Smuzhiyun  * @kbuf:	The kbuffer
765*4882a593Smuzhiyun  * @subbuf:	Start of mapped subbuffer
766*4882a593Smuzhiyun  * @info:	Info descriptor to fill in
767*4882a593Smuzhiyun  *
768*4882a593Smuzhiyun  * For debugging. This can return internals of the ring buffer.
769*4882a593Smuzhiyun  * Expects to have info->next set to what it will read.
770*4882a593Smuzhiyun  * The type, length and timestamp delta will be filled in, and
771*4882a593Smuzhiyun  * @info->next will be updated to the next element.
772*4882a593Smuzhiyun  * The @subbuf is used to know if the info is passed the end of
773*4882a593Smuzhiyun  * data and NULL will be returned if it is.
774*4882a593Smuzhiyun  */
775*4882a593Smuzhiyun struct kbuffer_raw_info *
kbuffer_raw_get(struct kbuffer * kbuf,void * subbuf,struct kbuffer_raw_info * info)776*4882a593Smuzhiyun kbuffer_raw_get(struct kbuffer *kbuf, void *subbuf, struct kbuffer_raw_info *info)
777*4882a593Smuzhiyun {
778*4882a593Smuzhiyun 	unsigned long long flags;
779*4882a593Smuzhiyun 	unsigned long long delta;
780*4882a593Smuzhiyun 	unsigned int type_len;
781*4882a593Smuzhiyun 	unsigned int size;
782*4882a593Smuzhiyun 	int start;
783*4882a593Smuzhiyun 	int length;
784*4882a593Smuzhiyun 	void *ptr = info->next;
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	if (!kbuf || !subbuf)
787*4882a593Smuzhiyun 		return NULL;
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 	if (kbuf->flags & KBUFFER_FL_LONG_8)
790*4882a593Smuzhiyun 		start = 16;
791*4882a593Smuzhiyun 	else
792*4882a593Smuzhiyun 		start = 12;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	flags = read_long(kbuf, subbuf + 8);
795*4882a593Smuzhiyun 	size = (unsigned int)flags & COMMIT_MASK;
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	if (ptr < subbuf || ptr >= subbuf + start + size)
798*4882a593Smuzhiyun 		return NULL;
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 	type_len = translate_data(kbuf, ptr, &ptr, &delta, &length);
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	info->next = ptr + length;
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	info->type = type_len;
805*4882a593Smuzhiyun 	info->delta = delta;
806*4882a593Smuzhiyun 	info->length = length;
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	return info;
809*4882a593Smuzhiyun }
810