xref: /linux-6.15/kernel/trace/trace_seq.c (revision 12306276)
1 /*
2  * trace_seq.c
3  *
4  * Copyright (C) 2008-2014 Red Hat Inc, Steven Rostedt <[email protected]>
5  *
6  */
7 #include <linux/uaccess.h>
8 #include <linux/seq_file.h>
9 #include <linux/trace_seq.h>
10 
11 int trace_print_seq(struct seq_file *m, struct trace_seq *s)
12 {
13 	int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len;
14 	int ret;
15 
16 	ret = seq_write(m, s->buffer, len);
17 
18 	/*
19 	 * Only reset this buffer if we successfully wrote to the
20 	 * seq_file buffer.
21 	 */
22 	if (!ret)
23 		trace_seq_init(s);
24 
25 	return ret;
26 }
27 
28 /**
29  * trace_seq_printf - sequence printing of trace information
30  * @s: trace sequence descriptor
31  * @fmt: printf format string
32  *
33  * It returns 0 if the trace oversizes the buffer's free
34  * space, 1 otherwise.
35  *
36  * The tracer may use either sequence operations or its own
37  * copy to user routines. To simplify formating of a trace
38  * trace_seq_printf is used to store strings into a special
39  * buffer (@s). Then the output may be either used by
40  * the sequencer or pulled into another buffer.
41  */
42 int
43 trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
44 {
45 	int len = (PAGE_SIZE - 1) - s->len;
46 	va_list ap;
47 	int ret;
48 
49 	if (s->full || !len)
50 		return 0;
51 
52 	va_start(ap, fmt);
53 	ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
54 	va_end(ap);
55 
56 	/* If we can't write it all, don't bother writing anything */
57 	if (ret >= len) {
58 		s->full = 1;
59 		return 0;
60 	}
61 
62 	s->len += ret;
63 
64 	return 1;
65 }
66 EXPORT_SYMBOL_GPL(trace_seq_printf);
67 
68 /**
69  * trace_seq_bitmask - put a list of longs as a bitmask print output
70  * @s:		trace sequence descriptor
71  * @maskp:	points to an array of unsigned longs that represent a bitmask
72  * @nmaskbits:	The number of bits that are valid in @maskp
73  *
74  * It returns 0 if the trace oversizes the buffer's free
75  * space, 1 otherwise.
76  *
77  * Writes a ASCII representation of a bitmask string into @s.
78  */
79 int
80 trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
81 		  int nmaskbits)
82 {
83 	int len = (PAGE_SIZE - 1) - s->len;
84 	int ret;
85 
86 	if (s->full || !len)
87 		return 0;
88 
89 	ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits);
90 	s->len += ret;
91 
92 	return 1;
93 }
94 EXPORT_SYMBOL_GPL(trace_seq_bitmask);
95 
96 /**
97  * trace_seq_vprintf - sequence printing of trace information
98  * @s: trace sequence descriptor
99  * @fmt: printf format string
100  *
101  * The tracer may use either sequence operations or its own
102  * copy to user routines. To simplify formating of a trace
103  * trace_seq_printf is used to store strings into a special
104  * buffer (@s). Then the output may be either used by
105  * the sequencer or pulled into another buffer.
106  */
107 int
108 trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
109 {
110 	int len = (PAGE_SIZE - 1) - s->len;
111 	int ret;
112 
113 	if (s->full || !len)
114 		return 0;
115 
116 	ret = vsnprintf(s->buffer + s->len, len, fmt, args);
117 
118 	/* If we can't write it all, don't bother writing anything */
119 	if (ret >= len) {
120 		s->full = 1;
121 		return 0;
122 	}
123 
124 	s->len += ret;
125 
126 	return len;
127 }
128 EXPORT_SYMBOL_GPL(trace_seq_vprintf);
129 
130 int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
131 {
132 	int len = (PAGE_SIZE - 1) - s->len;
133 	int ret;
134 
135 	if (s->full || !len)
136 		return 0;
137 
138 	ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
139 
140 	/* If we can't write it all, don't bother writing anything */
141 	if (ret >= len) {
142 		s->full = 1;
143 		return 0;
144 	}
145 
146 	s->len += ret;
147 
148 	return len;
149 }
150 
151 /**
152  * trace_seq_puts - trace sequence printing of simple string
153  * @s: trace sequence descriptor
154  * @str: simple string to record
155  *
156  * The tracer may use either the sequence operations or its own
157  * copy to user routines. This function records a simple string
158  * into a special buffer (@s) for later retrieval by a sequencer
159  * or other mechanism.
160  */
161 int trace_seq_puts(struct trace_seq *s, const char *str)
162 {
163 	int len = strlen(str);
164 
165 	if (s->full)
166 		return 0;
167 
168 	if (len > ((PAGE_SIZE - 1) - s->len)) {
169 		s->full = 1;
170 		return 0;
171 	}
172 
173 	memcpy(s->buffer + s->len, str, len);
174 	s->len += len;
175 
176 	return len;
177 }
178 
179 int trace_seq_putc(struct trace_seq *s, unsigned char c)
180 {
181 	if (s->full)
182 		return 0;
183 
184 	if (s->len >= (PAGE_SIZE - 1)) {
185 		s->full = 1;
186 		return 0;
187 	}
188 
189 	s->buffer[s->len++] = c;
190 
191 	return 1;
192 }
193 EXPORT_SYMBOL(trace_seq_putc);
194 
195 int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len)
196 {
197 	if (s->full)
198 		return 0;
199 
200 	if (len > ((PAGE_SIZE - 1) - s->len)) {
201 		s->full = 1;
202 		return 0;
203 	}
204 
205 	memcpy(s->buffer + s->len, mem, len);
206 	s->len += len;
207 
208 	return len;
209 }
210 
211 #define HEX_CHARS		(MAX_MEMHEX_BYTES*2 + 1)
212 
213 int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, size_t len)
214 {
215 	unsigned char hex[HEX_CHARS];
216 	const unsigned char *data = mem;
217 	int i, j;
218 
219 	if (s->full)
220 		return 0;
221 
222 #ifdef __BIG_ENDIAN
223 	for (i = 0, j = 0; i < len; i++) {
224 #else
225 	for (i = len-1, j = 0; i >= 0; i--) {
226 #endif
227 		hex[j++] = hex_asc_hi(data[i]);
228 		hex[j++] = hex_asc_lo(data[i]);
229 	}
230 	hex[j++] = ' ';
231 
232 	return trace_seq_putmem(s, hex, j);
233 }
234 
235 void *trace_seq_reserve(struct trace_seq *s, size_t len)
236 {
237 	void *ret;
238 
239 	if (s->full)
240 		return NULL;
241 
242 	if (len > ((PAGE_SIZE - 1) - s->len)) {
243 		s->full = 1;
244 		return NULL;
245 	}
246 
247 	ret = s->buffer + s->len;
248 	s->len += len;
249 
250 	return ret;
251 }
252 
253 int trace_seq_path(struct trace_seq *s, const struct path *path)
254 {
255 	unsigned char *p;
256 
257 	if (s->full)
258 		return 0;
259 
260 	if (s->len >= (PAGE_SIZE - 1)) {
261 		s->full = 1;
262 		return 0;
263 	}
264 
265 	p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
266 	if (!IS_ERR(p)) {
267 		p = mangle_path(s->buffer + s->len, p, "\n");
268 		if (p) {
269 			s->len = p - s->buffer;
270 			return 1;
271 		}
272 	} else {
273 		s->buffer[s->len++] = '?';
274 		return 1;
275 	}
276 
277 	s->full = 1;
278 	return 0;
279 }
280 
281 ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt)
282 {
283 	int len;
284 	int ret;
285 
286 	if (!cnt)
287 		return 0;
288 
289 	if (s->len <= s->readpos)
290 		return -EBUSY;
291 
292 	len = s->len - s->readpos;
293 	if (cnt > len)
294 		cnt = len;
295 	ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt);
296 	if (ret == cnt)
297 		return -EFAULT;
298 
299 	cnt -= ret;
300 
301 	s->readpos += cnt;
302 	return cnt;
303 }
304