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

TOMOYO Linux Cross Reference
Linux/arch/loongarch/kernel/unwind_prologue.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ 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.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /arch/loongarch/kernel/unwind_prologue.c (Architecture ppc) and /arch/alpha/kernel/unwind_prologue.c (Architecture alpha)


  1 // SPDX-License-Identifier: GPL-2.0                 1 
  2 /*                                                
  3  * Copyright (C) 2022 Loongson Technology Corp    
  4  */                                               
  5 #include <linux/cpumask.h>                        
  6 #include <linux/ftrace.h>                         
  7 #include <linux/kallsyms.h>                       
  8                                                   
  9 #include <asm/inst.h>                             
 10 #include <asm/loongson.h>                         
 11 #include <asm/ptrace.h>                           
 12 #include <asm/setup.h>                            
 13 #include <asm/unwind.h>                           
 14                                                   
 15 extern const int unwind_hint_ade;                 
 16 extern const int unwind_hint_ale;                 
 17 extern const int unwind_hint_bp;                  
 18 extern const int unwind_hint_fpe;                 
 19 extern const int unwind_hint_fpu;                 
 20 extern const int unwind_hint_lsx;                 
 21 extern const int unwind_hint_lasx;                
 22 extern const int unwind_hint_lbt;                 
 23 extern const int unwind_hint_ri;                  
 24 extern const int unwind_hint_watch;               
 25 extern unsigned long eentry;                      
 26 #ifdef CONFIG_NUMA                                
 27 extern unsigned long pcpu_handlers[NR_CPUS];      
 28 #endif                                            
 29                                                   
 30 static inline bool scan_handlers(unsigned long    
 31 {                                                 
 32         int idx, offset;                          
 33                                                   
 34         if (entry_offset >= EXCCODE_INT_START     
 35                 return false;                     
 36                                                   
 37         idx = entry_offset / VECSIZE;             
 38         offset = entry_offset % VECSIZE;          
 39         switch (idx) {                            
 40         case EXCCODE_ADE:                         
 41                 return offset == unwind_hint_a    
 42         case EXCCODE_ALE:                         
 43                 return offset == unwind_hint_a    
 44         case EXCCODE_BP:                          
 45                 return offset == unwind_hint_b    
 46         case EXCCODE_FPE:                         
 47                 return offset == unwind_hint_f    
 48         case EXCCODE_FPDIS:                       
 49                 return offset == unwind_hint_f    
 50         case EXCCODE_LSXDIS:                      
 51                 return offset == unwind_hint_l    
 52         case EXCCODE_LASXDIS:                     
 53                 return offset == unwind_hint_l    
 54         case EXCCODE_BTDIS:                       
 55                 return offset == unwind_hint_l    
 56         case EXCCODE_INE:                         
 57                 return offset == unwind_hint_r    
 58         case EXCCODE_WATCH:                       
 59                 return offset == unwind_hint_w    
 60         default:                                  
 61                 return false;                     
 62         }                                         
 63 }                                                 
 64                                                   
 65 static inline bool fix_exception(unsigned long    
 66 {                                                 
 67 #ifdef CONFIG_NUMA                                
 68         int cpu;                                  
 69                                                   
 70         for_each_possible_cpu(cpu) {              
 71                 if (!pcpu_handlers[cpu])          
 72                         continue;                 
 73                 if (scan_handlers(pc - pcpu_ha    
 74                         return true;              
 75         }                                         
 76 #endif                                            
 77         return scan_handlers(pc - eentry);        
 78 }                                                 
 79                                                   
 80 /*                                                
 81  * As we meet ftrace_regs_entry, reset first f    
 82  * tracing. Prologue analysis will stop soon b    
 83  */                                               
 84 static inline bool fix_ftrace(unsigned long pc    
 85 {                                                 
 86 #ifdef CONFIG_DYNAMIC_FTRACE                      
 87         return pc == (unsigned long)ftrace_cal    
 88 #else                                             
 89         return false;                             
 90 #endif                                            
 91 }                                                 
 92                                                   
 93 static inline bool unwind_state_fixup(struct u    
 94 {                                                 
 95         if (!fix_exception(state->pc) && !fix_    
 96                 return false;                     
 97                                                   
 98         state->reset = true;                      
 99         return true;                              
100 }                                                 
101                                                   
102 /*                                                
103  * LoongArch function prologue is like follows    
104  *     [instructions not use stack var]           
105  *     addi.d sp, sp, -imm                        
106  *     st.d   xx, sp, offset <- save callee sa    
107  *     st.d   yy, sp, offset    save ra if fun    
108  *     [others instructions]                      
109  */                                               
110 static bool unwind_by_prologue(struct unwind_s    
111 {                                                 
112         long frame_ra = -1;                       
113         unsigned long frame_size = 0;             
114         unsigned long size, offset, pc;           
115         struct pt_regs *regs;                     
116         struct stack_info *info = &state->stac    
117         union loongarch_instruction *ip, *ip_e    
118                                                   
119         if (state->sp >= info->end || state->s    
120                 return false;                     
121                                                   
122         if (state->reset) {                       
123                 regs = (struct pt_regs *)state    
124                 state->first = true;              
125                 state->reset = false;             
126                 state->pc = regs->csr_era;        
127                 state->ra = regs->regs[1];        
128                 state->sp = regs->regs[3];        
129                 return true;                      
130         }                                         
131                                                   
132         /*                                        
133          * When first is not set, the PC is a     
134          * We need to adjust its value in case    
135          */                                       
136         pc = state->pc - (state->first ? 0 : L    
137         if (!kallsyms_lookup_size_offset(pc, &    
138                 return false;                     
139                                                   
140         ip = (union loongarch_instruction *)(p    
141         ip_end = (union loongarch_instruction     
142                                                   
143         while (ip < ip_end) {                     
144                 if (is_stack_alloc_ins(ip)) {     
145                         frame_size = (1 << 12)    
146                         ip++;                     
147                         break;                    
148                 }                                 
149                 ip++;                             
150         }                                         
151                                                   
152         /*                                        
153          * Can't find stack alloc action, PC m    
154          * first being true is reasonable, oth    
155          */                                       
156         if (!frame_size) {                        
157                 if (state->first)                 
158                         goto first;               
159                                                   
160                 return false;                     
161         }                                         
162                                                   
163         while (ip < ip_end) {                     
164                 if (is_ra_save_ins(ip)) {         
165                         frame_ra = ip->reg2i12    
166                         break;                    
167                 }                                 
168                 if (is_branch_ins(ip))            
169                         break;                    
170                 ip++;                             
171         }                                         
172                                                   
173         /* Can't find save $ra action, PC may     
174         if (frame_ra < 0) {                       
175                 if (state->first) {               
176                         state->sp = state->sp     
177                         goto first;               
178                 }                                 
179                 return false;                     
180         }                                         
181                                                   
182         state->pc = *(unsigned long *)(state->    
183         state->sp = state->sp + frame_size;       
184         goto out;                                 
185                                                   
186 first:                                            
187         state->pc = state->ra;                    
188                                                   
189 out:                                              
190         state->first = false;                     
191         return unwind_state_fixup(state) || __    
192 }                                                 
193                                                   
194 static bool next_frame(struct unwind_state *st    
195 {                                                 
196         unsigned long pc;                         
197         struct pt_regs *regs;                     
198         struct stack_info *info = &state->stac    
199                                                   
200         if (unwind_done(state))                   
201                 return false;                     
202                                                   
203         do {                                      
204                 if (unwind_by_prologue(state))    
205                         state->pc = unwind_gra    
206                         return true;              
207                 }                                 
208                                                   
209                 if (info->type == STACK_TYPE_I    
210                         regs = (struct pt_regs    
211                         pc = regs->csr_era;       
212                                                   
213                         if (user_mode(regs) ||    
214                                 goto out;         
215                                                   
216                         state->first = true;      
217                         state->pc = pc;           
218                         state->ra = regs->regs    
219                         state->sp = regs->regs    
220                         get_stack_info(state->    
221                                                   
222                         return true;              
223                 }                                 
224                                                   
225                 state->sp = info->next_sp;        
226                                                   
227         } while (!get_stack_info(state->sp, st    
228                                                   
229 out:                                              
230         state->stack_info.type = STACK_TYPE_UN    
231         return false;                             
232 }                                                 
233                                                   
234 unsigned long unwind_get_return_address(struct    
235 {                                                 
236         return __unwind_get_return_address(sta    
237 }                                                 
238 EXPORT_SYMBOL_GPL(unwind_get_return_address);     
239                                                   
240 void unwind_start(struct unwind_state *state,     
241                     struct pt_regs *regs)         
242 {                                                 
243         __unwind_start(state, task, regs);        
244         state->type = UNWINDER_PROLOGUE;          
245         state->first = true;                      
246                                                   
247         /*                                        
248          * The current PC is not kernel text a    
249          * relative symbol. Thus, prologue ana    
250          * we can use the default_next_frame()    
251          */                                       
252         if (!__kernel_text_address(state->pc))    
253                 state->type = UNWINDER_GUESS;     
254                 if (!unwind_done(state))          
255                         unwind_next_frame(stat    
256         }                                         
257 }                                                 
258 EXPORT_SYMBOL_GPL(unwind_start);                  
259                                                   
260 bool unwind_next_frame(struct unwind_state *st    
261 {                                                 
262         return state->type == UNWINDER_PROLOGU    
263                         next_frame(state) : de    
264 }                                                 
265 EXPORT_SYMBOL_GPL(unwind_next_frame);             
266                                                   

~ [ 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