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

TOMOYO Linux Cross Reference
Linux/arch/arc/kernel/unwind.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/arc/kernel/unwind.c (Version linux-6.12-rc7) and /arch/sparc/kernel/unwind.c (Version linux-6.7.12)


  1 // SPDX-License-Identifier: GPL-2.0-only            1 
  2 /*                                                
  3  * Copyright (C) 2007-2010, 2011-2012 Synopsys    
  4  * Copyright (C) 2002-2006 Novell, Inc.           
  5  *      Jan Beulich <jbeulich@novell.com>         
  6  *                                                
  7  * A simple API for unwinding kernel stacks.      
  8  * debugging and error reporting purposes.  Th    
  9  * full-blown stack unwinding with all the bel    
 10  * is not much point in implementing the full     
 11  */                                               
 12                                                   
 13 #include <linux/sched.h>                          
 14 #include <linux/module.h>                         
 15 #include <linux/memblock.h>                       
 16 #include <linux/sort.h>                           
 17 #include <linux/slab.h>                           
 18 #include <linux/stop_machine.h>                   
 19 #include <linux/uaccess.h>                        
 20 #include <linux/ptrace.h>                         
 21 #include <asm/sections.h>                         
 22 #include <linux/unaligned.h>                      
 23 #include <asm/unwind.h>                           
 24                                                   
 25 extern char __start_unwind[], __end_unwind[];     
 26 /* extern const u8 __start_unwind_hdr[], __end    
 27                                                   
 28 /* #define UNWIND_DEBUG */                        
 29                                                   
 30 #ifdef UNWIND_DEBUG                               
 31 int dbg_unw;                                      
 32 #define unw_debug(fmt, ...)                       
 33 do {                                              
 34         if (dbg_unw)                              
 35                 pr_info(fmt, ##__VA_ARGS__);      
 36 } while (0);                                      
 37 #else                                             
 38 #define unw_debug(fmt, ...)                       
 39 #endif                                            
 40                                                   
 41 #define MAX_STACK_DEPTH 8                         
 42                                                   
 43 #define EXTRA_INFO(f) { \                         
 44                 BUILD_BUG_ON_ZERO(offsetof(str    
 45                                 % sizeof_field    
 46                                 + offsetof(str    
 47                                 / sizeof_field    
 48                                 sizeof_field(s    
 49         }                                         
 50 #define PTREGS_INFO(f) EXTRA_INFO(regs.f)         
 51                                                   
 52 static const struct {                             
 53         unsigned offs:BITS_PER_LONG / 2;          
 54         unsigned width:BITS_PER_LONG / 2;         
 55 } reg_info[] = {                                  
 56 UNW_REGISTER_INFO};                               
 57                                                   
 58 #undef PTREGS_INFO                                
 59 #undef EXTRA_INFO                                 
 60                                                   
 61 #ifndef REG_INVALID                               
 62 #define REG_INVALID(r) (reg_info[r].width == 0    
 63 #endif                                            
 64                                                   
 65 #define DW_CFA_nop                          0x    
 66 #define DW_CFA_set_loc                      0x    
 67 #define DW_CFA_advance_loc1                 0x    
 68 #define DW_CFA_advance_loc2                 0x    
 69 #define DW_CFA_advance_loc4                 0x    
 70 #define DW_CFA_offset_extended              0x    
 71 #define DW_CFA_restore_extended             0x    
 72 #define DW_CFA_undefined                    0x    
 73 #define DW_CFA_same_value                   0x    
 74 #define DW_CFA_register                     0x    
 75 #define DW_CFA_remember_state               0x    
 76 #define DW_CFA_restore_state                0x    
 77 #define DW_CFA_def_cfa                      0x    
 78 #define DW_CFA_def_cfa_register             0x    
 79 #define DW_CFA_def_cfa_offset               0x    
 80 #define DW_CFA_def_cfa_expression           0x    
 81 #define DW_CFA_expression                   0x    
 82 #define DW_CFA_offset_extended_sf           0x    
 83 #define DW_CFA_def_cfa_sf                   0x    
 84 #define DW_CFA_def_cfa_offset_sf            0x    
 85 #define DW_CFA_val_offset                   0x    
 86 #define DW_CFA_val_offset_sf                0x    
 87 #define DW_CFA_val_expression               0x    
 88 #define DW_CFA_lo_user                      0x    
 89 #define DW_CFA_GNU_window_save              0x    
 90 #define DW_CFA_GNU_args_size                0x    
 91 #define DW_CFA_GNU_negative_offset_extended 0x    
 92 #define DW_CFA_hi_user                      0x    
 93                                                   
 94 #define DW_EH_PE_FORM     0x07                    
 95 #define DW_EH_PE_native   0x00                    
 96 #define DW_EH_PE_leb128   0x01                    
 97 #define DW_EH_PE_data2    0x02                    
 98 #define DW_EH_PE_data4    0x03                    
 99 #define DW_EH_PE_data8    0x04                    
100 #define DW_EH_PE_signed   0x08                    
101 #define DW_EH_PE_ADJUST   0x70                    
102 #define DW_EH_PE_abs      0x00                    
103 #define DW_EH_PE_pcrel    0x10                    
104 #define DW_EH_PE_textrel  0x20                    
105 #define DW_EH_PE_datarel  0x30                    
106 #define DW_EH_PE_funcrel  0x40                    
107 #define DW_EH_PE_aligned  0x50                    
108 #define DW_EH_PE_indirect 0x80                    
109 #define DW_EH_PE_omit     0xff                    
110                                                   
111 #define CIE_ID  0                                 
112                                                   
113 typedef unsigned long uleb128_t;                  
114 typedef signed long sleb128_t;                    
115                                                   
116 static struct unwind_table {                      
117         struct {                                  
118                 unsigned long pc;                 
119                 unsigned long range;              
120         } core, init;                             
121         const void *address;                      
122         unsigned long size;                       
123         const unsigned char *header;              
124         unsigned long hdrsz;                      
125         struct unwind_table *link;                
126         const char *name;                         
127 } root_table;                                     
128                                                   
129 struct unwind_item {                              
130         enum item_location {                      
131                 Nowhere,                          
132                 Memory,                           
133                 Register,                         
134                 Value                             
135         } where;                                  
136         uleb128_t value;                          
137 };                                                
138                                                   
139 struct unwind_state {                             
140         uleb128_t loc, org;                       
141         const u8 *cieStart, *cieEnd;              
142         uleb128_t codeAlign;                      
143         sleb128_t dataAlign;                      
144         struct cfa {                              
145                 uleb128_t reg, offs;              
146         } cfa;                                    
147         struct unwind_item regs[ARRAY_SIZE(reg    
148         unsigned stackDepth:8;                    
149         unsigned version:8;                       
150         const u8 *label;                          
151         const u8 *stack[MAX_STACK_DEPTH];         
152 };                                                
153                                                   
154 static const struct cfa badCFA = { ARRAY_SIZE(    
155                                                   
156 static struct unwind_table *find_table(unsigne    
157 {                                                 
158         struct unwind_table *table;               
159                                                   
160         for (table = &root_table; table; table    
161                 if ((pc >= table->core.pc         
162                      && pc < table->core.pc +     
163                     || (pc >= table->init.pc      
164                         && pc < table->init.pc    
165                         break;                    
166                                                   
167         return table;                             
168 }                                                 
169                                                   
170 static unsigned long read_pointer(const u8 **p    
171                                   const void *    
172 static void init_unwind_hdr(struct unwind_tabl    
173                             void *(*alloc) (un    
174                                                   
175 /*                                                
176  * wrappers for header alloc (vs. calling one     
177  * to elide section mismatches warnings           
178  */                                               
179 static void *__init unw_hdr_alloc_early(unsign    
180 {                                                 
181         return memblock_alloc_from(sz, sizeof(    
182 }                                                 
183                                                   
184 static void init_unwind_table(struct unwind_ta    
185                               const void *core    
186                               const void *init    
187                               const void *tabl    
188                               const u8 *header    
189 {                                                 
190         table->core.pc = (unsigned long)core_s    
191         table->core.range = core_size;            
192         table->init.pc = (unsigned long)init_s    
193         table->init.range = init_size;            
194         table->address = table_start;             
195         table->size = table_size;                 
196         /* To avoid the pointer addition with     
197         if (header_start != NULL) {               
198                 const u8 *ptr = header_start +    
199                 const u8 *end = header_start +    
200                 /* See if the linker provided     
201                 if (header_size <= 4              
202                 || header_start[0] != 1           
203                 || (void *)read_pointer(&ptr,     
204                                 != table_start    
205                 || header_start[2] == DW_EH_PE    
206                 || read_pointer(&ptr, end, hea    
207                 || header_start[3] == DW_EH_PE    
208                         header_start = NULL;      
209         }                                         
210         table->hdrsz = header_size;               
211         smp_wmb();                                
212         table->header = header_start;             
213         table->link = NULL;                       
214         table->name = name;                       
215 }                                                 
216                                                   
217 void __init arc_unwind_init(void)                 
218 {                                                 
219         init_unwind_table(&root_table, "kernel    
220                           __start_unwind, __en    
221                           NULL, 0);               
222           /*__start_unwind_hdr, __end_unwind_h    
223                                                   
224         init_unwind_hdr(&root_table, unw_hdr_a    
225 }                                                 
226                                                   
227 static const u32 bad_cie, not_fde;                
228 static const u32 *cie_for_fde(const u32 *fde,     
229 static const u32 *__cie_for_fde(const u32 *fde    
230 static signed fde_pointer_type(const u32 *cie)    
231                                                   
232 struct eh_frame_hdr_table_entry {                 
233         unsigned long start, fde;                 
234 };                                                
235                                                   
236 static int cmp_eh_frame_hdr_table_entries(cons    
237 {                                                 
238         const struct eh_frame_hdr_table_entry     
239         const struct eh_frame_hdr_table_entry     
240                                                   
241         return (e1->start > e2->start) - (e1->    
242 }                                                 
243                                                   
244 static void swap_eh_frame_hdr_table_entries(vo    
245 {                                                 
246         struct eh_frame_hdr_table_entry *e1 =     
247         struct eh_frame_hdr_table_entry *e2 =     
248                                                   
249         swap(e1->start, e2->start);               
250         swap(e1->fde, e2->fde);                   
251 }                                                 
252                                                   
253 static void init_unwind_hdr(struct unwind_tabl    
254                             void *(*alloc) (un    
255 {                                                 
256         const u8 *ptr;                            
257         unsigned long tableSize = table->size,    
258         unsigned int n;                           
259         const u32 *fde;                           
260         struct {                                  
261                 u8 version;                       
262                 u8 eh_frame_ptr_enc;              
263                 u8 fde_count_enc;                 
264                 u8 table_enc;                     
265                 unsigned long eh_frame_ptr;       
266                 unsigned int fde_count;           
267                 struct eh_frame_hdr_table_entr    
268         } __attribute__ ((__packed__)) *header    
269                                                   
270         if (table->header)                        
271                 return;                           
272                                                   
273         if (table->hdrsz)                         
274                 pr_warn(".eh_frame_hdr for '%s    
275                         table->name);             
276                                                   
277         if (tableSize & (sizeof(*fde) - 1))       
278                 return;                           
279                                                   
280         for (fde = table->address, n = 0;         
281              tableSize > sizeof(*fde) && table    
282              tableSize -= sizeof(*fde) + *fde,    
283                 const u32 *cie = cie_for_fde(f    
284                 signed ptrType;                   
285                                                   
286                 if (cie == &not_fde)              
287                         continue;                 
288                 if (cie == NULL || cie == &bad    
289                         goto ret_err;             
290                 ptrType = fde_pointer_type(cie    
291                 if (ptrType < 0)                  
292                         goto ret_err;             
293                                                   
294                 ptr = (const u8 *)(fde + 2);      
295                 if (!read_pointer(&ptr, (const    
296                                                   
297                         /* FIXME_Rajesh We hav    
298                          * instead of the init    
299                          * return;                
300                          */                       
301                         WARN(1, "unwinder: FDE    
302                                 (const u8 *)(f    
303                 }                                 
304                 ++n;                              
305         }                                         
306                                                   
307         if (tableSize || !n)                      
308                 goto ret_err;                     
309                                                   
310         hdrSize = 4 + sizeof(unsigned long) +     
311             + 2 * n * sizeof(unsigned long);      
312                                                   
313         header = alloc(hdrSize);                  
314         if (!header)                              
315                 goto ret_err;                     
316                                                   
317         header->version = 1;                      
318         header->eh_frame_ptr_enc = DW_EH_PE_ab    
319         header->fde_count_enc = DW_EH_PE_abs |    
320         header->table_enc = DW_EH_PE_abs | DW_    
321         put_unaligned((unsigned long)table->ad    
322         BUILD_BUG_ON(offsetof(typeof(*header),    
323                      % __alignof(typeof(header    
324         header->fde_count = n;                    
325                                                   
326         BUILD_BUG_ON(offsetof(typeof(*header),    
327                      % __alignof(typeof(*heade    
328         for (fde = table->address, tableSize =    
329              tableSize;                           
330              tableSize -= sizeof(*fde) + *fde,    
331                 const u32 *cie = __cie_for_fde    
332                                                   
333                 if (fde[1] == CIE_ID)             
334                         continue;       /* thi    
335                 ptr = (const u8 *)(fde + 2);      
336                 header->table[n].start = read_    
337                                                   
338                                                   
339                                                   
340                 header->table[n].fde = (unsign    
341                 ++n;                              
342         }                                         
343         WARN_ON(n != header->fde_count);          
344                                                   
345         sort(header->table,                       
346              n,                                   
347              sizeof(*header->table),              
348              cmp_eh_frame_hdr_table_entries, s    
349                                                   
350         table->hdrsz = hdrSize;                   
351         smp_wmb();                                
352         table->header = (const void *)header;     
353         return;                                   
354                                                   
355 ret_err:                                          
356         panic("Attention !!! Dwarf FDE parsing    
357 }                                                 
358                                                   
359 #ifdef CONFIG_MODULES                             
360 static void *unw_hdr_alloc(unsigned long sz)      
361 {                                                 
362         return kmalloc(sz, GFP_KERNEL);           
363 }                                                 
364                                                   
365 static struct unwind_table *last_table;           
366                                                   
367 /* Must be called with module_mutex held. */      
368 void *unwind_add_table(struct module *module,     
369                        unsigned long table_siz    
370 {                                                 
371         struct unwind_table *table;               
372         struct module_memory *core_text;          
373         struct module_memory *init_text;          
374                                                   
375         if (table_size <= 0)                      
376                 return NULL;                      
377                                                   
378         table = kmalloc(sizeof(*table), GFP_KE    
379         if (!table)                               
380                 return NULL;                      
381                                                   
382         core_text = &module->mem[MOD_TEXT];       
383         init_text = &module->mem[MOD_INIT_TEXT    
384                                                   
385         init_unwind_table(table, module->name,    
386                           init_text->base, ini    
387                                                   
388         init_unwind_hdr(table, unw_hdr_alloc);    
389                                                   
390 #ifdef UNWIND_DEBUG                               
391         unw_debug("Table added for [%s] %lx %l    
392                 module->name, table->core.pc,     
393 #endif                                            
394         if (last_table)                           
395                 last_table->link = table;         
396         else                                      
397                 root_table.link = table;          
398         last_table = table;                       
399                                                   
400         return table;                             
401 }                                                 
402                                                   
403 struct unlink_table_info {                        
404         struct unwind_table *table;               
405         int init_only;                            
406 };                                                
407                                                   
408 static int unlink_table(void *arg)                
409 {                                                 
410         struct unlink_table_info *info = arg;     
411         struct unwind_table *table = info->tab    
412                                                   
413         for (prev = &root_table; prev->link &&    
414              prev = prev->link)                   
415                 ;                                 
416                                                   
417         if (prev->link) {                         
418                 if (info->init_only) {            
419                         table->init.pc = 0;       
420                         table->init.range = 0;    
421                         info->table = NULL;       
422                 } else {                          
423                         prev->link = table->li    
424                         if (!prev->link)          
425                                 last_table = p    
426                 }                                 
427         } else                                    
428                 info->table = NULL;               
429                                                   
430         return 0;                                 
431 }                                                 
432                                                   
433 /* Must be called with module_mutex held. */      
434 void unwind_remove_table(void *handle, int ini    
435 {                                                 
436         struct unwind_table *table = handle;      
437         struct unlink_table_info info;            
438                                                   
439         if (!table || table == &root_table)       
440                 return;                           
441                                                   
442         if (init_only && table == last_table)     
443                 table->init.pc = 0;               
444                 table->init.range = 0;            
445                 return;                           
446         }                                         
447                                                   
448         info.table = table;                       
449         info.init_only = init_only;               
450                                                   
451         unlink_table(&info); /* XXX: SMP */       
452         kfree(table->header);                     
453         kfree(table);                             
454 }                                                 
455                                                   
456 #endif /* CONFIG_MODULES */                       
457                                                   
458 static uleb128_t get_uleb128(const u8 **pcur,     
459 {                                                 
460         const u8 *cur = *pcur;                    
461         uleb128_t value;                          
462         unsigned int shift;                       
463                                                   
464         for (shift = 0, value = 0; cur < end;     
465                 if (shift + 7 > 8 * sizeof(val    
466                     && (*cur & 0x7fU) >= (1U <    
467                         cur = end + 1;            
468                         break;                    
469                 }                                 
470                 value |= (uleb128_t) (*cur & 0    
471                 if (!(*cur++ & 0x80))             
472                         break;                    
473         }                                         
474         *pcur = cur;                              
475                                                   
476         return value;                             
477 }                                                 
478                                                   
479 static sleb128_t get_sleb128(const u8 **pcur,     
480 {                                                 
481         const u8 *cur = *pcur;                    
482         sleb128_t value;                          
483         unsigned int shift;                       
484                                                   
485         for (shift = 0, value = 0; cur < end;     
486                 if (shift + 7 > 8 * sizeof(val    
487                     && (*cur & 0x7fU) >= (1U <    
488                         cur = end + 1;            
489                         break;                    
490                 }                                 
491                 value |= (sleb128_t) (*cur & 0    
492                 if (!(*cur & 0x80)) {             
493                         value |= -(*cur++ & 0x    
494                         break;                    
495                 }                                 
496         }                                         
497         *pcur = cur;                              
498                                                   
499         return value;                             
500 }                                                 
501                                                   
502 static const u32 *__cie_for_fde(const u32 *fde    
503 {                                                 
504         const u32 *cie;                           
505                                                   
506         cie = fde + 1 - fde[1] / sizeof(*fde);    
507                                                   
508         return cie;                               
509 }                                                 
510                                                   
511 static const u32 *cie_for_fde(const u32 *fde,     
512 {                                                 
513         const u32 *cie;                           
514                                                   
515         if (!*fde || (*fde & (sizeof(*fde) - 1    
516                 return &bad_cie;                  
517                                                   
518         if (fde[1] == CIE_ID)                     
519                 return &not_fde;        /* thi    
520                                                   
521         if ((fde[1] & (sizeof(*fde) - 1)))        
522 /* || fde[1] > (unsigned long)(fde + 1) - (uns    
523                 return NULL;    /* this is not    
524                                                   
525         cie = __cie_for_fde(fde);                 
526                                                   
527         if (*cie <= sizeof(*cie) + 4 || *cie >    
528             || (*cie & (sizeof(*cie) - 1))        
529             || (cie[1] != CIE_ID))                
530                 return NULL;    /* this is not    
531         return cie;                               
532 }                                                 
533                                                   
534 static unsigned long read_pointer(const u8 **p    
535                                   signed ptrTy    
536 {                                                 
537         unsigned long value = 0;                  
538         union {                                   
539                 const u8 *p8;                     
540                 const u16 *p16u;                  
541                 const s16 *p16s;                  
542                 const u32 *p32u;                  
543                 const s32 *p32s;                  
544                 const unsigned long *pul;         
545         } ptr;                                    
546                                                   
547         if (ptrType < 0 || ptrType == DW_EH_PE    
548                 return 0;                         
549         ptr.p8 = *pLoc;                           
550         switch (ptrType & DW_EH_PE_FORM) {        
551         case DW_EH_PE_data2:                      
552                 if (end < (const void *)(ptr.p    
553                         return 0;                 
554                 if (ptrType & DW_EH_PE_signed)    
555                         value = get_unaligned(    
556                 else                              
557                         value = get_unaligned(    
558                 break;                            
559         case DW_EH_PE_data4:                      
560 #ifdef CONFIG_64BIT                               
561                 if (end < (const void *)(ptr.p    
562                         return 0;                 
563                 if (ptrType & DW_EH_PE_signed)    
564                         value = get_unaligned(    
565                 else                              
566                         value = get_unaligned(    
567                 break;                            
568         case DW_EH_PE_data8:                      
569                 BUILD_BUG_ON(sizeof(u64) != si    
570 #else                                             
571                 BUILD_BUG_ON(sizeof(u32) != si    
572 #endif                                            
573                 fallthrough;                      
574         case DW_EH_PE_native:                     
575                 if (end < (const void *)(ptr.p    
576                         return 0;                 
577                 value = get_unaligned((unsigne    
578                 break;                            
579         case DW_EH_PE_leb128:                     
580                 BUILD_BUG_ON(sizeof(uleb128_t)    
581                 value = ptrType & DW_EH_PE_sig    
582                     : get_uleb128(&ptr.p8, end    
583                 if ((const void *)ptr.p8 > end    
584                         return 0;                 
585                 break;                            
586         default:                                  
587                 return 0;                         
588         }                                         
589         switch (ptrType & DW_EH_PE_ADJUST) {      
590         case DW_EH_PE_abs:                        
591                 break;                            
592         case DW_EH_PE_pcrel:                      
593                 value += (unsigned long)*pLoc;    
594                 break;                            
595         default:                                  
596                 return 0;                         
597         }                                         
598         if ((ptrType & DW_EH_PE_indirect)         
599             && __get_user(value, (unsigned lon    
600                 return 0;                         
601         *pLoc = ptr.p8;                           
602                                                   
603         return value;                             
604 }                                                 
605                                                   
606 static signed fde_pointer_type(const u32 *cie)    
607 {                                                 
608         const u8 *ptr = (const u8 *)(cie + 2);    
609         unsigned int version = *ptr;              
610                                                   
611         if (*++ptr) {                             
612                 const char *aug;                  
613                 const u8 *end = (const u8 *)(c    
614                 uleb128_t len;                    
615                                                   
616                 /* check if augmentation size     
617                 if (*ptr != 'z')                  
618                         return -1;                
619                                                   
620                 /* check if augmentation strin    
621                 aug = (const void *)ptr;          
622                 ptr = memchr(aug, 0, end - ptr    
623                 if (ptr == NULL)                  
624                         return -1;                
625                                                   
626                 ++ptr;          /* skip termin    
627                 get_uleb128(&ptr, end); /* ski    
628                 get_sleb128(&ptr, end); /* ski    
629                 /* skip return address column     
630                 version <= 1 ? (void) ++ptr :     
631                 len = get_uleb128(&ptr, end);     
632                                                   
633                 if (ptr + len < ptr || ptr + l    
634                         return -1;                
635                                                   
636                 end = ptr + len;                  
637                 while (*++aug) {                  
638                         if (ptr >= end)           
639                                 return -1;        
640                         switch (*aug) {           
641                         case 'L':                 
642                                 ++ptr;            
643                                 break;            
644                         case 'P':{                
645                                         signed    
646                                                   
647                                         if (!r    
648                                             ||    
649                                                   
650                                 }                 
651                                 break;            
652                         case 'R':                 
653                                 return *ptr;      
654                         default:                  
655                                 return -1;        
656                         }                         
657                 }                                 
658         }                                         
659         return DW_EH_PE_native | DW_EH_PE_abs;    
660 }                                                 
661                                                   
662 static int advance_loc(unsigned long delta, st    
663 {                                                 
664         state->loc += delta * state->codeAlign    
665                                                   
666         /* FIXME_Rajesh: Probably we are defin    
667            return delta > 0;                      
668          */                                       
669         unw_debug("delta %3lu => loc 0x%lx: ",    
670         return 1;                                 
671 }                                                 
672                                                   
673 static void set_rule(uleb128_t reg, enum item_    
674                      struct unwind_state *stat    
675 {                                                 
676         if (reg < ARRAY_SIZE(state->regs)) {      
677                 state->regs[reg].where = where    
678                 state->regs[reg].value = value    
679                                                   
680 #ifdef UNWIND_DEBUG                               
681                 unw_debug("r%lu: ", reg);         
682                 switch (where) {                  
683                 case Nowhere:                     
684                         unw_debug("s ");          
685                         break;                    
686                 case Memory:                      
687                         unw_debug("c(%lu) ", v    
688                         break;                    
689                 case Register:                    
690                         unw_debug("r(%lu) ", v    
691                         break;                    
692                 case Value:                       
693                         unw_debug("v(%lu) ", v    
694                         break;                    
695                 default:                          
696                         break;                    
697                 }                                 
698 #endif                                            
699         }                                         
700 }                                                 
701                                                   
702 static int processCFI(const u8 *start, const u    
703                       signed ptrType, struct u    
704 {                                                 
705         union {                                   
706                 const u8 *p8;                     
707                 const u16 *p16;                   
708                 const u32 *p32;                   
709         } ptr;                                    
710         int result = 1;                           
711         u8 opcode;                                
712                                                   
713         if (start != state->cieStart) {           
714                 state->loc = state->org;          
715                 result =                          
716                     processCFI(state->cieStart    
717                                state);            
718                 if (targetLoc == 0 && state->l    
719                         return result;            
720         }                                         
721         for (ptr.p8 = start; result && ptr.p8     
722                 switch (*ptr.p8 >> 6) {           
723                         uleb128_t value;          
724                                                   
725                 case 0:                           
726                         opcode = *ptr.p8++;       
727                                                   
728                         switch (opcode) {         
729                         case DW_CFA_nop:          
730                                 unw_debug("cfa    
731                                 break;            
732                         case DW_CFA_set_loc:      
733                                 state->loc = r    
734                                                   
735                                 if (state->loc    
736                                         result    
737                                 unw_debug("cfa    
738                                 break;            
739                         case DW_CFA_advance_lo    
740                                 unw_debug("\nc    
741                                 result = ptr.p    
742                                     && advance    
743                                 break;            
744                         case DW_CFA_advance_lo    
745                                 value = *ptr.p    
746                                 value += *ptr.    
747                                 unw_debug("\nc    
748                                 result = ptr.p    
749                                     /* && adva    
750                                     && advance    
751                                 break;            
752                         case DW_CFA_advance_lo    
753                                 unw_debug("\nc    
754                                 result = ptr.p    
755                                     && advance    
756                                 break;            
757                         case DW_CFA_offset_ext    
758                                 value = get_ul    
759                                 unw_debug("cfa    
760                                 set_rule(value    
761                                          get_u    
762                                 break;            
763                         case DW_CFA_val_offset    
764                                 value = get_ul    
765                                 set_rule(value    
766                                          get_u    
767                                 break;            
768                         case DW_CFA_offset_ext    
769                                 value = get_ul    
770                                 set_rule(value    
771                                          get_s    
772                                 break;            
773                         case DW_CFA_val_offset    
774                                 value = get_ul    
775                                 set_rule(value    
776                                          get_s    
777                                 break;            
778                         case DW_CFA_restore_ex    
779                                 unw_debug("cfa    
780                         case DW_CFA_undefined:    
781                                 unw_debug("cfa    
782                         case DW_CFA_same_value    
783                                 unw_debug("cfa    
784                                 set_rule(get_u    
785                                          state    
786                                 break;            
787                         case DW_CFA_register:     
788                                 unw_debug("cfa    
789                                 value = get_ul    
790                                 set_rule(value    
791                                          Regis    
792                                          get_u    
793                                 break;            
794                         case DW_CFA_remember_s    
795                                 unw_debug("cfa    
796                                 if (ptr.p8 ==     
797                                         state-    
798                                         return    
799                                 }                 
800                                 if (state->sta    
801                                         return    
802                                 state->stack[s    
803                                 break;            
804                         case DW_CFA_restore_st    
805                                 unw_debug("cfa    
806                                 if (state->sta    
807                                         const     
808                                         const     
809                                                   
810                                         state-    
811                                             st    
812                                         memcpy    
813                                                   
814                                         memset    
815                                                   
816                                         state-    
817                                         result    
818                                             pr    
819                                                   
820                                         state-    
821                                         state-    
822                                 } else            
823                                         return    
824                                 break;            
825                         case DW_CFA_def_cfa:      
826                                 state->cfa.reg    
827                                 unw_debug("cfa    
828                                 fallthrough;      
829                         case DW_CFA_def_cfa_of    
830                                 state->cfa.off    
831                                 unw_debug("cfa    
832                                           stat    
833                                 break;            
834                         case DW_CFA_def_cfa_sf    
835                                 state->cfa.reg    
836                                 fallthrough;      
837                         case DW_CFA_def_cfa_of    
838                                 state->cfa.off    
839                                     * state->d    
840                                 break;            
841                         case DW_CFA_def_cfa_re    
842                                 unw_debug("cfa    
843                                 state->cfa.reg    
844                                 break;            
845                                 /*todo case DW    
846                                 /*todo case DW    
847                                 /*todo case DW    
848                         case DW_CFA_GNU_args_s    
849                                 get_uleb128(&p    
850                                 break;            
851                         case DW_CFA_GNU_negati    
852                                 value = get_ul    
853                                 set_rule(value    
854                                          Memor    
855                                          (uleb    
856                                                   
857                                          state    
858                                 break;            
859                         case DW_CFA_GNU_window    
860                         default:                  
861                                 unw_debug("UNK    
862                                 result = 0;       
863                                 break;            
864                         }                         
865                         break;                    
866                 case 1:                           
867                         unw_debug("\ncfa_adv_l    
868                         result = advance_loc(*    
869                         break;                    
870                 case 2:                           
871                         unw_debug("cfa_offset:    
872                         value = *ptr.p8++ & 0x    
873                         set_rule(value, Memory    
874                                  state);          
875                         break;                    
876                 case 3:                           
877                         unw_debug("cfa_restore    
878                         set_rule(*ptr.p8++ & 0    
879                         break;                    
880                 }                                 
881                                                   
882                 if (ptr.p8 > end)                 
883                         result = 0;               
884                 if (result && targetLoc != 0 &    
885                         return 1;                 
886         }                                         
887                                                   
888         return result && ptr.p8 == end && (tar    
889                 /*todo While in theory this sh    
890                   everything past the function    
891                   never reaches the end of the    
892                 targetLoc < state->loc && */      
893 }                                                 
894                                                   
895 /* Unwind to previous to frame.  Returns 0 if     
896  * number in case of an error. */                 
897 int arc_unwind(struct unwind_frame_info *frame    
898 {                                                 
899 #define FRAME_REG(r, t) (((t *)frame)[reg_info    
900         const u32 *fde = NULL, *cie = NULL;       
901         const u8 *ptr = NULL, *end = NULL;        
902         unsigned long pc = UNW_PC(frame) - fra    
903         unsigned long startLoc = 0, endLoc = 0    
904         unsigned int i;                           
905         signed ptrType = -1;                      
906         uleb128_t retAddrReg = 0;                 
907         const struct unwind_table *table;         
908         struct unwind_state state;                
909         unsigned long *fptr;                      
910         unsigned long addr;                       
911                                                   
912         unw_debug("\n\nUNWIND FRAME:\n");         
913         unw_debug("PC: 0x%lx BLINK: 0x%lx, SP:    
914                   UNW_PC(frame), UNW_BLINK(fra    
915                   UNW_FP(frame));                 
916                                                   
917         if (UNW_PC(frame) == 0)                   
918                 return -EINVAL;                   
919                                                   
920 #ifdef UNWIND_DEBUG                               
921         {                                         
922                 unsigned long *sptr = (unsigne    
923                 unw_debug("\nStack Dump:\n");     
924                 for (i = 0; i < 20; i++, sptr+    
925                         unw_debug("0x%p:  0x%l    
926                 unw_debug("\n");                  
927         }                                         
928 #endif                                            
929                                                   
930         table = find_table(pc);                   
931         if (table != NULL                         
932             && !(table->size & (sizeof(*fde) -    
933                 const u8 *hdr = table->header;    
934                 unsigned long tableSize;          
935                                                   
936                 smp_rmb();                        
937                 if (hdr && hdr[0] == 1) {         
938                         switch (hdr[3] & DW_EH    
939                         case DW_EH_PE_native:     
940                                 tableSize = si    
941                                 break;            
942                         case DW_EH_PE_data2:      
943                                 tableSize = 2;    
944                                 break;            
945                         case DW_EH_PE_data4:      
946                                 tableSize = 4;    
947                                 break;            
948                         case DW_EH_PE_data8:      
949                                 tableSize = 8;    
950                                 break;            
951                         default:                  
952                                 tableSize = 0;    
953                                 break;            
954                         }                         
955                         ptr = hdr + 4;            
956                         end = hdr + table->hdr    
957                         if (tableSize && read_    
958                             == (unsigned long)    
959                             && (i = read_point    
960                             && i == (end - ptr    
961                             && !((end - ptr) %    
962                                 do {              
963                                         const     
964                                             pt    
965                                                   
966                                         startL    
967                                                   
968                                                   
969                                         if (pc    
970                                                   
971                                         else {    
972                                                   
973                                                   
974                                         }         
975                                 } while (start    
976                                 if (i == 1        
977                                     && (startL    
978                                                   
979                                                   
980                                     && pc >= s    
981                                         fde =     
982                                                   
983                                                   
984                                                   
985                         }                         
986                 }                                 
987                                                   
988                 if (fde != NULL) {                
989                         cie = cie_for_fde(fde,    
990                         ptr = (const u8 *)(fde    
991                         if (cie != NULL           
992                             && cie != &bad_cie    
993                             && cie != &not_fde    
994                             && (ptrType = fde_    
995                             && read_pointer(&p    
996                                             (c    
997                                             pt    
998                                 if (!(ptrType     
999                                         ptrTyp    
1000                                             D    
1001                                 endLoc =         
1002                                     startLoc     
1003                                                  
1004                                                  
1005                                                  
1006                                 if (pc >= end    
1007                                         fde =    
1008                                         cie =    
1009                                 }                
1010                         } else {                 
1011                                 fde = NULL;      
1012                                 cie = NULL;      
1013                         }                        
1014                 }                                
1015         }                                        
1016         if (cie != NULL) {                       
1017                 memset(&state, 0, sizeof(stat    
1018                 state.cieEnd = ptr;     /* ke    
1019                 ptr = (const u8 *)(cie + 2);     
1020                 end = (const u8 *)(cie + 1) +    
1021                 frame->call_frame = 1;           
1022                 if (*++ptr) {                    
1023                         /* check if augmentat    
1024                         if (*ptr == 'z') {       
1025                                 while (++ptr     
1026                                         switc    
1027                                         /* ch    
1028                                          * nu    
1029                                         case     
1030                                         case     
1031                                         case     
1032                                                  
1033                                         case     
1034                                                  
1035                                                  
1036                                         defau    
1037                                                  
1038                                         }        
1039                                         break    
1040                                 }                
1041                         }                        
1042                         if (ptr >= end || *pt    
1043                                 cie = NULL;      
1044                 }                                
1045                 ++ptr;                           
1046         }                                        
1047         if (cie != NULL) {                       
1048                 /* get code alignment factor     
1049                 state.codeAlign = get_uleb128    
1050                 /* get data alignment factor     
1051                 state.dataAlign = get_sleb128    
1052                 if (state.codeAlign == 0 || s    
1053                         cie = NULL;              
1054                 else {                           
1055                         retAddrReg =             
1056                             state.version <=     
1057                                                  
1058                         unw_debug("CIE Frame     
1059                         unw_debug("return Add    
1060                                   retAddrReg)    
1061                         unw_debug("data Align    
1062                         unw_debug("code Align    
1063                         /* skip augmentation     
1064                         if (((const char *)(c    
1065                                 uleb128_t aug    
1066                                                  
1067                                 ptr += augSiz    
1068                         }                        
1069                         if (ptr > end || retA    
1070                             || REG_INVALID(re    
1071                             || reg_info[retAd    
1072                             sizeof(unsigned l    
1073                                 cie = NULL;      
1074                 }                                
1075         }                                        
1076         if (cie != NULL) {                       
1077                 state.cieStart = ptr;            
1078                 ptr = state.cieEnd;              
1079                 state.cieEnd = end;              
1080                 end = (const u8 *)(fde + 1) +    
1081                 /* skip augmentation */          
1082                 if (((const char *)(cie + 2))    
1083                         uleb128_t augSize = g    
1084                                                  
1085                         if ((ptr += augSize)     
1086                                 fde = NULL;      
1087                 }                                
1088         }                                        
1089         if (cie == NULL || fde == NULL) {        
1090 #ifdef CONFIG_FRAME_POINTER                      
1091                 unsigned long top, bottom;       
1092                                                  
1093                 top = STACK_TOP_UNW(frame->ta    
1094                 bottom = STACK_BOTTOM_UNW(fra    
1095 #if FRAME_RETADDR_OFFSET < 0                     
1096                 if (UNW_SP(frame) < top && UN    
1097                     && bottom < UNW_FP(frame)    
1098 #else                                            
1099                 if (UNW_SP(frame) > top && UN    
1100                     && bottom > UNW_FP(frame)    
1101 #endif                                           
1102                     && !((UNW_SP(frame) | UNW    
1103                          & (sizeof(unsigned l    
1104                         unsigned long link;      
1105                                                  
1106                         if (!__get_user(link,    
1107                                         (UNW_    
1108 #if FRAME_RETADDR_OFFSET < 0                     
1109                             && link > bottom     
1110 #else                                            
1111                             && link > UNW_FP(    
1112 #endif                                           
1113                             && !(link & (size    
1114                             && !__get_user(UN    
1115                                            (u    
1116                                                  
1117                         {                        
1118                                 UNW_SP(frame)    
1119                                     UNW_FP(fr    
1120 #if FRAME_RETADDR_OFFSET < 0                     
1121                                     -            
1122 #else                                            
1123                                     +            
1124 #endif                                           
1125                                     sizeof(UN    
1126                                 UNW_FP(frame)    
1127                                 return 0;        
1128                         }                        
1129                 }                                
1130 #endif                                           
1131                 return -ENXIO;                   
1132         }                                        
1133         state.org = startLoc;                    
1134         memcpy(&state.cfa, &badCFA, sizeof(st    
1135                                                  
1136         unw_debug("\nProcess instructions\n")    
1137                                                  
1138         /* process instructions                  
1139          * For ARC, we optimize by having bli    
1140          * the sameValue in the leaf function    
1141          * state.regs[retAddrReg].where == No    
1142          */                                      
1143         if (!processCFI(ptr, end, pc, ptrType    
1144             || state.loc > endLoc                
1145 /*         || state.regs[retAddrReg].where ==    
1146             || state.cfa.reg >= ARRAY_SIZE(re    
1147             || reg_info[state.cfa.reg].width     
1148             || state.cfa.offs % sizeof(unsign    
1149                 return -EIO;                     
1150                                                  
1151 #ifdef UNWIND_DEBUG                              
1152         unw_debug("\n");                         
1153                                                  
1154         unw_debug("\nRegister State Based on     
1155         for (i = 0; i < ARRAY_SIZE(state.regs    
1156                                                  
1157                 if (REG_INVALID(i))              
1158                         continue;                
1159                                                  
1160                 switch (state.regs[i].where)     
1161                 case Nowhere:                    
1162                         break;                   
1163                 case Memory:                     
1164                         unw_debug(" r%d: c(%l    
1165                         break;                   
1166                 case Register:                   
1167                         unw_debug(" r%d: r(%l    
1168                         break;                   
1169                 case Value:                      
1170                         unw_debug(" r%d: v(%l    
1171                         break;                   
1172                 }                                
1173         }                                        
1174                                                  
1175         unw_debug("\n");                         
1176 #endif                                           
1177                                                  
1178         /* update frame */                       
1179         if (frame->call_frame                    
1180             && !UNW_DEFAULT_RA(state.regs[ret    
1181                 frame->call_frame = 0;           
1182         cfa = FRAME_REG(state.cfa.reg, unsign    
1183         startLoc = min_t(unsigned long, UNW_S    
1184         endLoc = max_t(unsigned long, UNW_SP(    
1185         if (STACK_LIMIT(startLoc) != STACK_LI    
1186                 startLoc = min(STACK_LIMIT(cf    
1187                 endLoc = max(STACK_LIMIT(cfa)    
1188         }                                        
1189                                                  
1190         unw_debug("\nCFA reg: 0x%lx, offset:     
1191                   state.cfa.reg, state.cfa.of    
1192                                                  
1193         for (i = 0; i < ARRAY_SIZE(state.regs    
1194                 if (REG_INVALID(i)) {            
1195                         if (state.regs[i].whe    
1196                                 continue;        
1197                         return -EIO;             
1198                 }                                
1199                 switch (state.regs[i].where)     
1200                 default:                         
1201                         break;                   
1202                 case Register:                   
1203                         if (state.regs[i].val    
1204                             || REG_INVALID(st    
1205                             || reg_info[i].wi    
1206                             reg_info[state.re    
1207                                 return -EIO;     
1208                         switch (reg_info[stat    
1209                         case sizeof(u8):         
1210                                 state.regs[i]    
1211                                 FRAME_REG(sta    
1212                                 break;           
1213                         case sizeof(u16):        
1214                                 state.regs[i]    
1215                                 FRAME_REG(sta    
1216                                 break;           
1217                         case sizeof(u32):        
1218                                 state.regs[i]    
1219                                 FRAME_REG(sta    
1220                                 break;           
1221 #ifdef CONFIG_64BIT                              
1222                         case sizeof(u64):        
1223                                 state.regs[i]    
1224                                 FRAME_REG(sta    
1225                                 break;           
1226 #endif                                           
1227                         default:                 
1228                                 return -EIO;     
1229                         }                        
1230                         break;                   
1231                 }                                
1232         }                                        
1233                                                  
1234         unw_debug("\nRegister state after eva    
1235         fptr = (unsigned long *)(&frame->regs    
1236         for (i = 0; i < ARRAY_SIZE(state.regs    
1237                                                  
1238                 if (REG_INVALID(i))              
1239                         continue;                
1240                 switch (state.regs[i].where)     
1241                 case Nowhere:                    
1242                         if (reg_info[i].width    
1243                             || &FRAME_REG(i,     
1244                             != &UNW_SP(frame)    
1245                                 continue;        
1246                         UNW_SP(frame) = cfa;     
1247                         break;                   
1248                 case Register:                   
1249                         switch (reg_info[i].w    
1250                         case sizeof(u8):         
1251                                 FRAME_REG(i,     
1252                                 break;           
1253                         case sizeof(u16):        
1254                                 FRAME_REG(i,     
1255                                 break;           
1256                         case sizeof(u32):        
1257                                 FRAME_REG(i,     
1258                                 break;           
1259 #ifdef CONFIG_64BIT                              
1260                         case sizeof(u64):        
1261                                 FRAME_REG(i,     
1262                                 break;           
1263 #endif                                           
1264                         default:                 
1265                                 return -EIO;     
1266                         }                        
1267                         break;                   
1268                 case Value:                      
1269                         if (reg_info[i].width    
1270                                 return -EIO;     
1271                         FRAME_REG(i, unsigned    
1272                             * state.dataAlign    
1273                         break;                   
1274                 case Memory:                     
1275                         addr = cfa + state.re    
1276                                                  
1277                         if ((state.regs[i].va    
1278                             % sizeof(unsigned    
1279                             || addr < startLo    
1280                             || addr + sizeof(    
1281                             || addr + sizeof(    
1282                                         retur    
1283                                                  
1284                         switch (reg_info[i].w    
1285                         case sizeof(u8):         
1286                                 __get_user(FR    
1287                                            (u    
1288                                 break;           
1289                         case sizeof(u16):        
1290                                 __get_user(FR    
1291                                            (u    
1292                                 break;           
1293                         case sizeof(u32):        
1294                                 __get_user(FR    
1295                                            (u    
1296                                 break;           
1297 #ifdef CONFIG_64BIT                              
1298                         case sizeof(u64):        
1299                                 __get_user(FR    
1300                                            (u    
1301                                 break;           
1302 #endif                                           
1303                         default:                 
1304                                 return -EIO;     
1305                         }                        
1306                                                  
1307                         break;                   
1308                 }                                
1309                 unw_debug("r%d: 0x%lx ", i, *    
1310         }                                        
1311                                                  
1312         return 0;                                
1313 #undef FRAME_REG                                 
1314 }                                                
1315 EXPORT_SYMBOL(arc_unwind);                       
1316                                                  

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