Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /*
3 : : * This example code shows how to read from the trace buffer.
4 : : *
5 : : * Copyright 2013-2019 IBM Corp.
6 : : */
7 : :
8 : : #include <external/trace/trace.h>
9 : : #include "../ccan/endian/endian.h"
10 : : #include "../ccan/short_types/short_types.h"
11 : : #include "trace.h"
12 : : #include <trace_types.h>
13 : : #include <errno.h>
14 : :
15 : : #if defined(__powerpc__) || defined(__powerpc64__)
16 : : #define rmb() lwsync()
17 : : #else
18 : : #define rmb()
19 : : #endif
20 : :
21 : 3995508 : bool trace_empty(const struct trace_reader *tr)
22 : : {
23 : : const struct trace_repeat *rep;
24 : :
25 : 3995508 : if (tr->rpos == be64_to_cpu(tr->tb->end))
26 : 42 : return true;
27 : :
28 : : /*
29 : : * If we have a single element only, and it's a repeat buffer
30 : : * we've already seen every repeat for (yet which may be
31 : : * incremented in future), we're also empty.
32 : : */
33 : 3995466 : rep = (void *)tr->tb->buf + tr->rpos % be64_to_cpu(tr->tb->buf_size);
34 : 3995466 : if (be64_to_cpu(tr->tb->end) != tr->rpos + sizeof(*rep))
35 : 1902598 : return false;
36 : :
37 : 2092868 : if (rep->type != TRACE_REPEAT)
38 : 13 : return false;
39 : :
40 : 2092855 : if (be16_to_cpu(rep->num) != tr->last_repeat)
41 : 1046434 : return false;
42 : :
43 : 1046421 : return true;
44 : : }
45 : :
46 : : /* You can't read in parallel, so some locking required in caller. */
47 : 3995504 : bool trace_get(union trace *t, struct trace_reader *tr)
48 : : {
49 : : u64 start, rpos;
50 : : size_t len;
51 : :
52 : 7991008 : len = sizeof(*t) < be32_to_cpu(tr->tb->max_size) ? sizeof(*t) :
53 : 3995504 : be32_to_cpu(tr->tb->max_size);
54 : :
55 : 3995504 : if (trace_empty(tr))
56 : 1046459 : return false;
57 : :
58 : 2949045 : again:
59 : : /*
60 : : * The actual buffer is slightly larger than tbsize, so this
61 : : * memcpy is always valid.
62 : : */
63 : 3668529 : memcpy(t, tr->tb->buf + tr->rpos % be64_to_cpu(tr->tb->buf_size), len);
64 : :
65 : : rmb(); /* read barrier, so we read tr->tb->start after copying record. */
66 : :
67 : 3668529 : start = be64_to_cpu(tr->tb->start);
68 : 3668529 : rpos = tr->rpos;
69 : :
70 : : /* Now, was that overwritten? */
71 : 3668529 : if (rpos < start) {
72 : : /* Create overflow record. */
73 : 35 : t->overflow.unused64 = 0;
74 : 35 : t->overflow.type = TRACE_OVERFLOW;
75 : 35 : t->overflow.len_div_8 = sizeof(t->overflow) / 8;
76 : 35 : t->overflow.bytes_missed = cpu_to_be64(start - rpos);
77 : 35 : tr->rpos = start;
78 : 35 : return true;
79 : : }
80 : :
81 : : /* Repeat entries need special handling */
82 : 3668494 : if (t->hdr.type == TRACE_REPEAT) {
83 : 2485383 : u32 num = be16_to_cpu(t->repeat.num);
84 : :
85 : : /* In case we've read some already... */
86 : 2485383 : t->repeat.num = cpu_to_be16(num - tr->last_repeat);
87 : :
88 : : /* Record how many repeats we saw this time. */
89 : 2485383 : tr->last_repeat = num;
90 : :
91 : : /* Don't report an empty repeat buffer. */
92 : 2485383 : if (t->repeat.num == 0) {
93 : : /*
94 : : * This can't be the last buffer, otherwise
95 : : * trace_empty would have returned true.
96 : : */
97 : 719484 : assert(be64_to_cpu(tr->tb->end) >
98 : : rpos + t->hdr.len_div_8 * 8);
99 : : /* Skip to next entry. */
100 : 719484 : tr->rpos = rpos + t->hdr.len_div_8 * 8;
101 : 719484 : tr->last_repeat = 0;
102 : 719484 : goto again;
103 : : }
104 : : } else {
105 : 1183111 : tr->last_repeat = 0;
106 : 1183111 : tr->rpos = rpos + t->hdr.len_div_8 * 8;
107 : : }
108 : :
109 : 2949010 : return true;
110 : : }
|