~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm64/include/asm/stacktrace/common.h

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* SPDX-License-Identifier: GPL-2.0-only */
  2 /*
  3  * Common arm64 stack unwinder code.
  4  *
  5  * See: arch/arm64/kernel/stacktrace.c for the reference implementation.
  6  *
  7  * Copyright (C) 2012 ARM Ltd.
  8  */
  9 #ifndef __ASM_STACKTRACE_COMMON_H
 10 #define __ASM_STACKTRACE_COMMON_H
 11 
 12 #include <linux/types.h>
 13 
 14 struct stack_info {
 15         unsigned long low;
 16         unsigned long high;
 17 };
 18 
 19 /**
 20  * struct unwind_state - state used for robust unwinding.
 21  *
 22  * @fp:          The fp value in the frame record (or the real fp)
 23  * @pc:          The lr value in the frame record (or the real lr)
 24  *
 25  * @stack:       The stack currently being unwound.
 26  * @stacks:      An array of stacks which can be unwound.
 27  * @nr_stacks:   The number of stacks in @stacks.
 28  */
 29 struct unwind_state {
 30         unsigned long fp;
 31         unsigned long pc;
 32 
 33         struct stack_info stack;
 34         struct stack_info *stacks;
 35         int nr_stacks;
 36 };
 37 
 38 static inline struct stack_info stackinfo_get_unknown(void)
 39 {
 40         return (struct stack_info) {
 41                 .low = 0,
 42                 .high = 0,
 43         };
 44 }
 45 
 46 static inline bool stackinfo_on_stack(const struct stack_info *info,
 47                                       unsigned long sp, unsigned long size)
 48 {
 49         if (!info->low)
 50                 return false;
 51 
 52         if (sp < info->low || sp + size < sp || sp + size > info->high)
 53                 return false;
 54 
 55         return true;
 56 }
 57 
 58 static inline void unwind_init_common(struct unwind_state *state)
 59 {
 60         state->stack = stackinfo_get_unknown();
 61 }
 62 
 63 static struct stack_info *unwind_find_next_stack(const struct unwind_state *state,
 64                                                  unsigned long sp,
 65                                                  unsigned long size)
 66 {
 67         for (int i = 0; i < state->nr_stacks; i++) {
 68                 struct stack_info *info = &state->stacks[i];
 69 
 70                 if (stackinfo_on_stack(info, sp, size))
 71                         return info;
 72         }
 73 
 74         return NULL;
 75 }
 76 
 77 /**
 78  * unwind_consume_stack() - Check if an object is on an accessible stack,
 79  * updating stack boundaries so that future unwind steps cannot consume this
 80  * object again.
 81  *
 82  * @state: the current unwind state.
 83  * @sp:    the base address of the object.
 84  * @size:  the size of the object.
 85  *
 86  * Return: 0 upon success, an error code otherwise.
 87  */
 88 static inline int unwind_consume_stack(struct unwind_state *state,
 89                                        unsigned long sp,
 90                                        unsigned long size)
 91 {
 92         struct stack_info *next;
 93 
 94         if (stackinfo_on_stack(&state->stack, sp, size))
 95                 goto found;
 96 
 97         next = unwind_find_next_stack(state, sp, size);
 98         if (!next)
 99                 return -EINVAL;
100 
101         /*
102          * Stack transitions are strictly one-way, and once we've
103          * transitioned from one stack to another, it's never valid to
104          * unwind back to the old stack.
105          *
106          * Remove the current stack from the list of stacks so that it cannot
107          * be found on a subsequent transition.
108          *
109          * Note that stacks can nest in several valid orders, e.g.
110          *
111          *   TASK -> IRQ -> OVERFLOW -> SDEI_NORMAL
112          *   TASK -> SDEI_NORMAL -> SDEI_CRITICAL -> OVERFLOW
113          *   HYP -> OVERFLOW
114          *
115          * ... so we do not check the specific order of stack
116          * transitions.
117          */
118         state->stack = *next;
119         *next = stackinfo_get_unknown();
120 
121 found:
122         /*
123          * Future unwind steps can only consume stack above this frame record.
124          * Update the current stack to start immediately above it.
125          */
126         state->stack.low = sp + size;
127         return 0;
128 }
129 
130 /**
131  * unwind_next_frame_record() - Unwind to the next frame record.
132  *
133  * @state:        the current unwind state.
134  *
135  * Return: 0 upon success, an error code otherwise.
136  */
137 static inline int
138 unwind_next_frame_record(struct unwind_state *state)
139 {
140         unsigned long fp = state->fp;
141         int err;
142 
143         if (fp & 0x7)
144                 return -EINVAL;
145 
146         err = unwind_consume_stack(state, fp, 16);
147         if (err)
148                 return err;
149 
150         /*
151          * Record this frame record's values.
152          */
153         state->fp = READ_ONCE(*(unsigned long *)(fp));
154         state->pc = READ_ONCE(*(unsigned long *)(fp + 8));
155 
156         return 0;
157 }
158 
159 #endif  /* __ASM_STACKTRACE_COMMON_H */
160 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php