1 /* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
3 * lttng-context-callstack-stackwalk-impl.h
5 * LTTng callstack event context, stackwalk implementation. Targets
6 * kernels and architectures using the stacktrace common infrastructure
7 * introduced in the upstream Linux kernel by commit 214d8ca6ee
8 * "stacktrace: Provide common infrastructure" (merged in Linux 5.2,
9 * then gradually introduced within architectures).
11 * Copyright (C) 2014-2019 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
12 * Copyright (C) 2014 Francis Giraldeau <francis.giraldeau@gmail.com>
15 #define MAX_ENTRIES 128
17 enum lttng_cs_ctx_modes
{
23 struct lttng_stack_trace
{
24 unsigned long entries
[MAX_ENTRIES
];
25 unsigned int nr_entries
;
29 struct lttng_stack_trace stack_trace
[RING_BUFFER_MAX_NESTING
];
33 struct lttng_cs __percpu
*cs_percpu
;
34 enum lttng_cs_ctx_modes mode
;
38 unsigned int (*save_func_kernel
)(unsigned long *store
, unsigned int size
,
41 unsigned int (*save_func_user
)(unsigned long *store
, unsigned int size
);
44 const char *lttng_cs_ctx_mode_name(enum lttng_cs_ctx_modes mode
)
47 case CALLSTACK_KERNEL
:
48 return "callstack_kernel";
50 return "callstack_user";
57 const char *lttng_cs_ctx_mode_length_name(enum lttng_cs_ctx_modes mode
)
60 case CALLSTACK_KERNEL
:
61 return "_callstack_kernel_length";
63 return "_callstack_user_length";
70 int init_type_callstack_kernel(void)
73 const char *func_name
= "stack_trace_save";
77 func
= kallsyms_lookup_funcptr(func_name
);
79 printk(KERN_WARNING
"LTTng: symbol lookup failed: %s\n",
83 save_func_kernel
= (void *) func
;
88 int init_type_callstack_user(void)
91 const char *func_name
= "stack_trace_save_user";
95 func
= kallsyms_lookup_funcptr(func_name
);
97 printk(KERN_WARNING
"LTTng: symbol lookup failed: %s\n",
101 save_func_user
= (void *) func
;
106 int init_type(enum lttng_cs_ctx_modes mode
)
109 case CALLSTACK_KERNEL
:
110 return init_type_callstack_kernel();
112 return init_type_callstack_user();
119 void lttng_cs_set_init(struct lttng_cs __percpu
*cs_set
)
123 /* Keep track of nesting inside userspace callstack context code */
124 DEFINE_PER_CPU(int, callstack_user_nesting
);
127 struct lttng_stack_trace
*stack_trace_context(struct lttng_ctx_field
*field
,
128 struct lib_ring_buffer_ctx
*ctx
)
130 int buffer_nesting
, cs_user_nesting
;
132 struct field_data
*fdata
= field
->priv
;
135 * Do not gather the userspace callstack context when the event was
136 * triggered by the userspace callstack context saving mechanism.
138 cs_user_nesting
= per_cpu(callstack_user_nesting
, ctx
->cpu
);
140 if (fdata
->mode
== CALLSTACK_USER
&& cs_user_nesting
>= 1)
144 * get_cpu() is not required, preemption is already
145 * disabled while event is written.
147 * max nesting is checked in lib_ring_buffer_get_cpu().
148 * Check it again as a safety net.
150 cs
= per_cpu_ptr(fdata
->cs_percpu
, ctx
->cpu
);
151 buffer_nesting
= per_cpu(lib_ring_buffer_nesting
, ctx
->cpu
) - 1;
152 if (buffer_nesting
>= RING_BUFFER_MAX_NESTING
)
155 return &cs
->stack_trace
[buffer_nesting
];
159 size_t lttng_callstack_length_get_size(size_t offset
, struct lttng_ctx_field
*field
,
160 struct lib_ring_buffer_ctx
*ctx
,
161 struct lttng_channel
*chan
)
163 size_t orig_offset
= offset
;
165 offset
+= lib_ring_buffer_align(offset
, lttng_alignof(unsigned int));
166 offset
+= sizeof(unsigned int);
167 return offset
- orig_offset
;
171 * In order to reserve the correct size, the callstack is computed. The
172 * resulting callstack is saved to be accessed in the record step.
175 size_t lttng_callstack_sequence_get_size(size_t offset
, struct lttng_ctx_field
*field
,
176 struct lib_ring_buffer_ctx
*ctx
,
177 struct lttng_channel
*chan
)
179 struct lttng_stack_trace
*trace
;
180 struct field_data
*fdata
= field
->priv
;
181 size_t orig_offset
= offset
;
183 /* do not write data if no space is available */
184 trace
= stack_trace_context(field
, ctx
);
185 if (unlikely(!trace
)) {
186 offset
+= lib_ring_buffer_align(offset
, lttng_alignof(unsigned long));
187 return offset
- orig_offset
;
190 /* reset stack trace, no need to clear memory */
191 trace
->nr_entries
= 0;
193 switch (fdata
->mode
) {
194 case CALLSTACK_KERNEL
:
195 /* do the real work and reserve space */
196 trace
->nr_entries
= save_func_kernel(trace
->entries
,
200 ++per_cpu(callstack_user_nesting
, ctx
->cpu
);
201 /* do the real work and reserve space */
202 trace
->nr_entries
= save_func_user(trace
->entries
,
204 per_cpu(callstack_user_nesting
, ctx
->cpu
)--;
211 * If the array is filled, add our own marker to show that the
212 * stack is incomplete.
214 offset
+= lib_ring_buffer_align(offset
, lttng_alignof(unsigned long));
215 offset
+= sizeof(unsigned long) * trace
->nr_entries
;
216 /* Add our own ULONG_MAX delimiter to show incomplete stack. */
217 if (trace
->nr_entries
== MAX_ENTRIES
)
218 offset
+= sizeof(unsigned long);
219 return offset
- orig_offset
;
223 void lttng_callstack_length_record(struct lttng_ctx_field
*field
,
224 struct lib_ring_buffer_ctx
*ctx
,
225 struct lttng_channel
*chan
)
227 struct lttng_stack_trace
*trace
= stack_trace_context(field
, ctx
);
228 unsigned int nr_seq_entries
;
230 lib_ring_buffer_align_ctx(ctx
, lttng_alignof(unsigned int));
231 if (unlikely(!trace
)) {
234 nr_seq_entries
= trace
->nr_entries
;
235 if (trace
->nr_entries
== MAX_ENTRIES
)
238 chan
->ops
->event_write(ctx
, &nr_seq_entries
, sizeof(unsigned int));
242 void lttng_callstack_sequence_record(struct lttng_ctx_field
*field
,
243 struct lib_ring_buffer_ctx
*ctx
,
244 struct lttng_channel
*chan
)
246 struct lttng_stack_trace
*trace
= stack_trace_context(field
, ctx
);
247 unsigned int nr_seq_entries
;
249 lib_ring_buffer_align_ctx(ctx
, lttng_alignof(unsigned long));
250 if (unlikely(!trace
)) {
253 nr_seq_entries
= trace
->nr_entries
;
254 if (trace
->nr_entries
== MAX_ENTRIES
)
256 chan
->ops
->event_write(ctx
, trace
->entries
,
257 sizeof(unsigned long) * trace
->nr_entries
);
258 /* Add our own ULONG_MAX delimiter to show incomplete stack. */
259 if (trace
->nr_entries
== MAX_ENTRIES
) {
260 unsigned long delim
= ULONG_MAX
;
262 chan
->ops
->event_write(ctx
, &delim
, sizeof(unsigned long));