Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _LINUX_TRACE_PRINTK_H
3#define _LINUX_TRACE_PRINTK_H
4
5#include <linux/compiler_attributes.h>
6#include <linux/instruction_pointer.h>
7#include <linux/stddef.h>
8#include <linux/stringify.h>
9
10/*
11 * General tracing related utility functions - trace_printk(),
12 * tracing_on/tracing_off and tracing_start()/tracing_stop
13 *
14 * Use tracing_on/tracing_off when you want to quickly turn on or off
15 * tracing. It simply enables or disables the recording of the trace events.
16 * This also corresponds to the user space /sys/kernel/tracing/tracing_on
17 * file, which gives a means for the kernel and userspace to interact.
18 * Place a tracing_off() in the kernel where you want tracing to end.
19 * From user space, examine the trace, and then echo 1 > tracing_on
20 * to continue tracing.
21 *
22 * tracing_stop/tracing_start has slightly more overhead. It is used
23 * by things like suspend to ram where disabling the recording of the
24 * trace is not enough, but tracing must actually stop because things
25 * like calling smp_processor_id() may crash the system.
26 *
27 * Most likely, you want to use tracing_on/tracing_off.
28 */
29
30enum ftrace_dump_mode {
31 DUMP_NONE,
32 DUMP_ALL,
33 DUMP_ORIG,
34 DUMP_PARAM,
35};
36
37#ifdef CONFIG_TRACING
38void tracing_on(void);
39void tracing_off(void);
40int tracing_is_on(void);
41void tracing_snapshot(void);
42void tracing_snapshot_alloc(void);
43
44extern void tracing_start(void);
45extern void tracing_stop(void);
46
47static inline __printf(1, 2)
48void ____trace_printk_check_format(const char *fmt, ...)
49{
50}
51#define __trace_printk_check_format(fmt, args...) \
52do { \
53 if (0) \
54 ____trace_printk_check_format(fmt, ##args); \
55} while (0)
56
57/**
58 * trace_printk - printf formatting in the ftrace buffer
59 * @fmt: the printf format for printing
60 *
61 * Note: __trace_printk is an internal function for trace_printk() and
62 * the @ip is passed in via the trace_printk() macro.
63 *
64 * This function allows a kernel developer to debug fast path sections
65 * that printk is not appropriate for. By scattering in various
66 * printk like tracing in the code, a developer can quickly see
67 * where problems are occurring.
68 *
69 * This is intended as a debugging tool for the developer only.
70 * Please refrain from leaving trace_printks scattered around in
71 * your code. (Extra memory is used for special buffers that are
72 * allocated when trace_printk() is used.)
73 *
74 * A little optimization trick is done here. If there's only one
75 * argument, there's no need to scan the string for printf formats.
76 * The trace_puts() will suffice. But how can we take advantage of
77 * using trace_puts() when trace_printk() has only one argument?
78 * By stringifying the args and checking the size we can tell
79 * whether or not there are args. __stringify((__VA_ARGS__)) will
80 * turn into "()\0" with a size of 3 when there are no args, anything
81 * else will be bigger. All we need to do is define a string to this,
82 * and then take its size and compare to 3. If it's bigger, use
83 * do_trace_printk() otherwise, optimize it to trace_puts(). Then just
84 * let gcc optimize the rest.
85 */
86
87#define trace_printk(fmt, ...) \
88do { \
89 char _______STR[] = __stringify((__VA_ARGS__)); \
90 if (sizeof(_______STR) > 3) \
91 do_trace_printk(fmt, ##__VA_ARGS__); \
92 else \
93 trace_puts(fmt); \
94} while (0)
95
96#define do_trace_printk(fmt, args...) \
97do { \
98 static const char *trace_printk_fmt __used \
99 __section("__trace_printk_fmt") = \
100 __builtin_constant_p(fmt) ? fmt : NULL; \
101 \
102 __trace_printk_check_format(fmt, ##args); \
103 \
104 if (__builtin_constant_p(fmt)) \
105 __trace_bprintk(_THIS_IP_, trace_printk_fmt, ##args); \
106 else \
107 __trace_printk(_THIS_IP_, fmt, ##args); \
108} while (0)
109
110int __trace_bprintk(unsigned long ip, const char *fmt, ...);
111
112extern __printf(2, 3)
113int __trace_printk(unsigned long ip, const char *fmt, ...);
114
115/**
116 * trace_puts - write a string into the ftrace buffer
117 * @str: the string to record
118 *
119 * Note: __trace_bputs is an internal function for trace_puts and
120 * the @ip is passed in via the trace_puts macro.
121 *
122 * This is similar to trace_printk() but is made for those really fast
123 * paths that a developer wants the least amount of "Heisenbug" effects,
124 * where the processing of the print format is still too much.
125 *
126 * This function allows a kernel developer to debug fast path sections
127 * that printk is not appropriate for. By scattering in various
128 * printk like tracing in the code, a developer can quickly see
129 * where problems are occurring.
130 *
131 * This is intended as a debugging tool for the developer only.
132 * Please refrain from leaving trace_puts scattered around in
133 * your code. (Extra memory is used for special buffers that are
134 * allocated when trace_puts() is used.)
135 *
136 * Returns: 0 if nothing was written, positive # if string was.
137 * (1 when __trace_bputs is used, strlen(str) when __trace_puts is used)
138 */
139
140#define trace_puts(str) ({ \
141 static const char *trace_printk_fmt __used \
142 __section("__trace_printk_fmt") = \
143 __builtin_constant_p(str) ? str : NULL; \
144 \
145 if (__builtin_constant_p(str)) \
146 __trace_bputs(_THIS_IP_, trace_printk_fmt); \
147 else \
148 __trace_puts(_THIS_IP_, str); \
149})
150extern int __trace_bputs(unsigned long ip, const char *str);
151extern int __trace_puts(unsigned long ip, const char *str);
152
153extern void trace_dump_stack(int skip);
154
155/*
156 * The double __builtin_constant_p is because gcc will give us an error
157 * if we try to allocate the static variable to fmt if it is not a
158 * constant. Even with the outer if statement.
159 */
160#define ftrace_vprintk(fmt, vargs) \
161do { \
162 if (__builtin_constant_p(fmt)) { \
163 static const char *trace_printk_fmt __used \
164 __section("__trace_printk_fmt") = \
165 __builtin_constant_p(fmt) ? fmt : NULL; \
166 \
167 __ftrace_vbprintk(_THIS_IP_, trace_printk_fmt, vargs); \
168 } else \
169 __ftrace_vprintk(_THIS_IP_, fmt, vargs); \
170} while (0)
171
172extern __printf(2, 0) int
173__ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap);
174
175extern __printf(2, 0) int
176__ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap);
177
178extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode);
179#else
180static inline void tracing_start(void) { }
181static inline void tracing_stop(void) { }
182static inline void trace_dump_stack(int skip) { }
183
184static inline void tracing_on(void) { }
185static inline void tracing_off(void) { }
186static inline int tracing_is_on(void) { return 0; }
187static inline void tracing_snapshot(void) { }
188static inline void tracing_snapshot_alloc(void) { }
189
190static inline __printf(1, 2)
191int trace_printk(const char *fmt, ...)
192{
193 return 0;
194}
195static __printf(1, 0) inline int
196ftrace_vprintk(const char *fmt, va_list ap)
197{
198 return 0;
199}
200static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
201#endif /* CONFIG_TRACING */
202
203#endif