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

TOMOYO Linux Cross Reference
Linux/arch/arc/kernel/unwind.c

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  * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
  4  * Copyright (C) 2002-2006 Novell, Inc.
  5  *      Jan Beulich <jbeulich@novell.com>
  6  *
  7  * A simple API for unwinding kernel stacks.  This is used for
  8  * debugging and error reporting purposes.  The kernel doesn't need
  9  * full-blown stack unwinding with all the bells and whistles, so there
 10  * is not much point in implementing the full Dwarf2 unwind API.
 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 <asm/unaligned.h>
 23 #include <asm/unwind.h>
 24 
 25 extern char __start_unwind[], __end_unwind[];
 26 /* extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];*/
 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(struct unwind_frame_info, f) \
 45                                 % sizeof_field(struct unwind_frame_info, f)) \
 46                                 + offsetof(struct unwind_frame_info, f) \
 47                                 / sizeof_field(struct unwind_frame_info, f), \
 48                                 sizeof_field(struct unwind_frame_info, f) \
 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                          0x00
 66 #define DW_CFA_set_loc                      0x01
 67 #define DW_CFA_advance_loc1                 0x02
 68 #define DW_CFA_advance_loc2                 0x03
 69 #define DW_CFA_advance_loc4                 0x04
 70 #define DW_CFA_offset_extended              0x05
 71 #define DW_CFA_restore_extended             0x06
 72 #define DW_CFA_undefined                    0x07
 73 #define DW_CFA_same_value                   0x08
 74 #define DW_CFA_register                     0x09
 75 #define DW_CFA_remember_state               0x0a
 76 #define DW_CFA_restore_state                0x0b
 77 #define DW_CFA_def_cfa                      0x0c
 78 #define DW_CFA_def_cfa_register             0x0d
 79 #define DW_CFA_def_cfa_offset               0x0e
 80 #define DW_CFA_def_cfa_expression           0x0f
 81 #define DW_CFA_expression                   0x10
 82 #define DW_CFA_offset_extended_sf           0x11
 83 #define DW_CFA_def_cfa_sf                   0x12
 84 #define DW_CFA_def_cfa_offset_sf            0x13
 85 #define DW_CFA_val_offset                   0x14
 86 #define DW_CFA_val_offset_sf                0x15
 87 #define DW_CFA_val_expression               0x16
 88 #define DW_CFA_lo_user                      0x1c
 89 #define DW_CFA_GNU_window_save              0x2d
 90 #define DW_CFA_GNU_args_size                0x2e
 91 #define DW_CFA_GNU_negative_offset_extended 0x2f
 92 #define DW_CFA_hi_user                      0x3f
 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_info)];
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(reg_info), 1 };
155 
156 static struct unwind_table *find_table(unsigned long pc)
157 {
158         struct unwind_table *table;
159 
160         for (table = &root_table; table; table = table->link)
161                 if ((pc >= table->core.pc
162                      && pc < table->core.pc + table->core.range)
163                     || (pc >= table->init.pc
164                         && pc < table->init.pc + table->init.range))
165                         break;
166 
167         return table;
168 }
169 
170 static unsigned long read_pointer(const u8 **pLoc,
171                                   const void *end, signed ptrType);
172 static void init_unwind_hdr(struct unwind_table *table,
173                             void *(*alloc) (unsigned long));
174 
175 /*
176  * wrappers for header alloc (vs. calling one vs. other at call site)
177  * to elide section mismatches warnings
178  */
179 static void *__init unw_hdr_alloc_early(unsigned long sz)
180 {
181         return memblock_alloc_from(sz, sizeof(unsigned int), MAX_DMA_ADDRESS);
182 }
183 
184 static void init_unwind_table(struct unwind_table *table, const char *name,
185                               const void *core_start, unsigned long core_size,
186                               const void *init_start, unsigned long init_size,
187                               const void *table_start, unsigned long table_size,
188                               const u8 *header_start, unsigned long header_size)
189 {
190         table->core.pc = (unsigned long)core_start;
191         table->core.range = core_size;
192         table->init.pc = (unsigned long)init_start;
193         table->init.range = init_size;
194         table->address = table_start;
195         table->size = table_size;
196         /* To avoid the pointer addition with NULL pointer.*/
197         if (header_start != NULL) {
198                 const u8 *ptr = header_start + 4;
199                 const u8 *end = header_start + header_size;
200                 /* See if the linker provided table looks valid. */
201                 if (header_size <= 4
202                 || header_start[0] != 1
203                 || (void *)read_pointer(&ptr, end, header_start[1])
204                                 != table_start
205                 || header_start[2] == DW_EH_PE_omit
206                 || read_pointer(&ptr, end, header_start[2]) <= 0
207                 || header_start[3] == DW_EH_PE_omit)
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", _text, _end - _text, NULL, 0,
220                           __start_unwind, __end_unwind - __start_unwind,
221                           NULL, 0);
222           /*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/
223 
224         init_unwind_hdr(&root_table, unw_hdr_alloc_early);
225 }
226 
227 static const u32 bad_cie, not_fde;
228 static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *);
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(const void *p1, const void *p2)
237 {
238         const struct eh_frame_hdr_table_entry *e1 = p1;
239         const struct eh_frame_hdr_table_entry *e2 = p2;
240 
241         return (e1->start > e2->start) - (e1->start < e2->start);
242 }
243 
244 static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size)
245 {
246         struct eh_frame_hdr_table_entry *e1 = p1;
247         struct eh_frame_hdr_table_entry *e2 = p2;
248 
249         swap(e1->start, e2->start);
250         swap(e1->fde, e2->fde);
251 }
252 
253 static void init_unwind_hdr(struct unwind_table *table,
254                             void *(*alloc) (unsigned long))
255 {
256         const u8 *ptr;
257         unsigned long tableSize = table->size, hdrSize;
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_entry table[];
268         } __attribute__ ((__packed__)) *header;
269 
270         if (table->header)
271                 return;
272 
273         if (table->hdrsz)
274                 pr_warn(".eh_frame_hdr for '%s' present but unusable\n",
275                         table->name);
276 
277         if (tableSize & (sizeof(*fde) - 1))
278                 return;
279 
280         for (fde = table->address, n = 0;
281              tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
282              tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
283                 const u32 *cie = cie_for_fde(fde, table);
284                 signed ptrType;
285 
286                 if (cie == &not_fde)
287                         continue;
288                 if (cie == NULL || cie == &bad_cie)
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 u8 *)(fde + 1) + *fde,
296                                                                 ptrType)) {
297                         /* FIXME_Rajesh We have 4 instances of null addresses
298                          * instead of the initial loc addr
299                          * return;
300                          */
301                         WARN(1, "unwinder: FDE->initial_location NULL %p\n",
302                                 (const u8 *)(fde + 1) + *fde);
303                 }
304                 ++n;
305         }
306 
307         if (tableSize || !n)
308                 goto ret_err;
309 
310         hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
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_abs | DW_EH_PE_native;
319         header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4;
320         header->table_enc = DW_EH_PE_abs | DW_EH_PE_native;
321         put_unaligned((unsigned long)table->address, &header->eh_frame_ptr);
322         BUILD_BUG_ON(offsetof(typeof(*header), fde_count)
323                      % __alignof(typeof(header->fde_count)));
324         header->fde_count = n;
325 
326         BUILD_BUG_ON(offsetof(typeof(*header), table)
327                      % __alignof(typeof(*header->table)));
328         for (fde = table->address, tableSize = table->size, n = 0;
329              tableSize;
330              tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
331                 const u32 *cie = __cie_for_fde(fde);
332 
333                 if (fde[1] == CIE_ID)
334                         continue;       /* this is a CIE */
335                 ptr = (const u8 *)(fde + 2);
336                 header->table[n].start = read_pointer(&ptr,
337                                                       (const u8 *)(fde + 1) +
338                                                       *fde,
339                                                       fde_pointer_type(cie));
340                 header->table[n].fde = (unsigned long)fde;
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, swap_eh_frame_hdr_table_entries);
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 errors\n");
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, const void *table_start,
369                        unsigned long table_size)
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_KERNEL);
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, core_text->base, core_text->size,
386                           init_text->base, init_text->size, table_start, table_size, NULL, 0);
387 
388         init_unwind_hdr(table, unw_hdr_alloc);
389 
390 #ifdef UNWIND_DEBUG
391         unw_debug("Table added for [%s] %lx %lx\n",
392                 module->name, table->core.pc, table->core.range);
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->table, *prev;
412 
413         for (prev = &root_table; prev->link && prev->link != table;
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->link;
424                         if (!prev->link)
425                                 last_table = prev;
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 init_only)
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, const u8 *end)
459 {
460         const u8 *cur = *pcur;
461         uleb128_t value;
462         unsigned int shift;
463 
464         for (shift = 0, value = 0; cur < end; shift += 7) {
465                 if (shift + 7 > 8 * sizeof(value)
466                     && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
467                         cur = end + 1;
468                         break;
469                 }
470                 value |= (uleb128_t) (*cur & 0x7f) << shift;
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, const u8 *end)
480 {
481         const u8 *cur = *pcur;
482         sleb128_t value;
483         unsigned int shift;
484 
485         for (shift = 0, value = 0; cur < end; shift += 7) {
486                 if (shift + 7 > 8 * sizeof(value)
487                     && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
488                         cur = end + 1;
489                         break;
490                 }
491                 value |= (sleb128_t) (*cur & 0x7f) << shift;
492                 if (!(*cur & 0x80)) {
493                         value |= -(*cur++ & 0x40) << shift;
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, const struct unwind_table *table)
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;        /* this is a CIE */
520 
521         if ((fde[1] & (sizeof(*fde) - 1)))
522 /* || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) */
523                 return NULL;    /* this is not a valid FDE */
524 
525         cie = __cie_for_fde(fde);
526 
527         if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde)
528             || (*cie & (sizeof(*cie) - 1))
529             || (cie[1] != CIE_ID))
530                 return NULL;    /* this is not a (valid) CIE */
531         return cie;
532 }
533 
534 static unsigned long read_pointer(const u8 **pLoc, const void *end,
535                                   signed ptrType)
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_omit)
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.p16u + 1))
553                         return 0;
554                 if (ptrType & DW_EH_PE_signed)
555                         value = get_unaligned((u16 *) ptr.p16s++);
556                 else
557                         value = get_unaligned((u16 *) ptr.p16u++);
558                 break;
559         case DW_EH_PE_data4:
560 #ifdef CONFIG_64BIT
561                 if (end < (const void *)(ptr.p32u + 1))
562                         return 0;
563                 if (ptrType & DW_EH_PE_signed)
564                         value = get_unaligned(ptr.p32s++);
565                 else
566                         value = get_unaligned(ptr.p32u++);
567                 break;
568         case DW_EH_PE_data8:
569                 BUILD_BUG_ON(sizeof(u64) != sizeof(value));
570 #else
571                 BUILD_BUG_ON(sizeof(u32) != sizeof(value));
572 #endif
573                 fallthrough;
574         case DW_EH_PE_native:
575                 if (end < (const void *)(ptr.pul + 1))
576                         return 0;
577                 value = get_unaligned((unsigned long *)ptr.pul++);
578                 break;
579         case DW_EH_PE_leb128:
580                 BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
581                 value = ptrType & DW_EH_PE_signed ? get_sleb128(&ptr.p8, end)
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 long __user *)value))
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 *)(cie + 1) + *cie;
614                 uleb128_t len;
615 
616                 /* check if augmentation size is first (and thus present) */
617                 if (*ptr != 'z')
618                         return -1;
619 
620                 /* check if augmentation string is nul-terminated */
621                 aug = (const void *)ptr;
622                 ptr = memchr(aug, 0, end - ptr);
623                 if (ptr == NULL)
624                         return -1;
625 
626                 ++ptr;          /* skip terminator */
627                 get_uleb128(&ptr, end); /* skip code alignment */
628                 get_sleb128(&ptr, end); /* skip data alignment */
629                 /* skip return address column */
630                 version <= 1 ? (void) ++ptr : (void)get_uleb128(&ptr, end);
631                 len = get_uleb128(&ptr, end);   /* augmentation length */
632 
633                 if (ptr + len < ptr || ptr + len > end)
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 ptrType = *ptr++;
646 
647                                         if (!read_pointer(&ptr, end, ptrType)
648                                             || ptr > end)
649                                                 return -1;
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, struct unwind_state *state)
663 {
664         state->loc += delta * state->codeAlign;
665 
666         /* FIXME_Rajesh: Probably we are defining for the initial range as well;
667            return delta > 0;
668          */
669         unw_debug("delta %3lu => loc 0x%lx: ", delta, state->loc);
670         return 1;
671 }
672 
673 static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value,
674                      struct unwind_state *state)
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) ", value);
688                         break;
689                 case Register:
690                         unw_debug("r(%lu) ", value);
691                         break;
692                 case Value:
693                         unw_debug("v(%lu) ", value);
694                         break;
695                 default:
696                         break;
697                 }
698 #endif
699         }
700 }
701 
702 static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
703                       signed ptrType, struct unwind_state *state)
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, state->cieEnd, 0, ptrType,
717                                state);
718                 if (targetLoc == 0 && state->label == NULL)
719                         return result;
720         }
721         for (ptr.p8 = start; result && ptr.p8 < end;) {
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 nop ");
731                                 break;
732                         case DW_CFA_set_loc:
733                                 state->loc = read_pointer(&ptr.p8, end,
734                                                           ptrType);
735                                 if (state->loc == 0)
736                                         result = 0;
737                                 unw_debug("cfa_set_loc: 0x%lx ", state->loc);
738                                 break;
739                         case DW_CFA_advance_loc1:
740                                 unw_debug("\ncfa advance loc1:");
741                                 result = ptr.p8 < end
742                                     && advance_loc(*ptr.p8++, state);
743                                 break;
744                         case DW_CFA_advance_loc2:
745                                 value = *ptr.p8++;
746                                 value += *ptr.p8++ << 8;
747                                 unw_debug("\ncfa advance loc2:");
748                                 result = ptr.p8 <= end + 2
749                                     /* && advance_loc(*ptr.p16++, state); */
750                                     && advance_loc(value, state);
751                                 break;
752                         case DW_CFA_advance_loc4:
753                                 unw_debug("\ncfa advance loc4:");
754                                 result = ptr.p8 <= end + 4
755                                     && advance_loc(*ptr.p32++, state);
756                                 break;
757                         case DW_CFA_offset_extended:
758                                 value = get_uleb128(&ptr.p8, end);
759                                 unw_debug("cfa_offset_extended: ");
760                                 set_rule(value, Memory,
761                                          get_uleb128(&ptr.p8, end), state);
762                                 break;
763                         case DW_CFA_val_offset:
764                                 value = get_uleb128(&ptr.p8, end);
765                                 set_rule(value, Value,
766                                          get_uleb128(&ptr.p8, end), state);
767                                 break;
768                         case DW_CFA_offset_extended_sf:
769                                 value = get_uleb128(&ptr.p8, end);
770                                 set_rule(value, Memory,
771                                          get_sleb128(&ptr.p8, end), state);
772                                 break;
773                         case DW_CFA_val_offset_sf:
774                                 value = get_uleb128(&ptr.p8, end);
775                                 set_rule(value, Value,
776                                          get_sleb128(&ptr.p8, end), state);
777                                 break;
778                         case DW_CFA_restore_extended:
779                                 unw_debug("cfa_restore_extended: ");
780                         case DW_CFA_undefined:
781                                 unw_debug("cfa_undefined: ");
782                         case DW_CFA_same_value:
783                                 unw_debug("cfa_same_value: ");
784                                 set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0,
785                                          state);
786                                 break;
787                         case DW_CFA_register:
788                                 unw_debug("cfa_register: ");
789                                 value = get_uleb128(&ptr.p8, end);
790                                 set_rule(value,
791                                          Register,
792                                          get_uleb128(&ptr.p8, end), state);
793                                 break;
794                         case DW_CFA_remember_state:
795                                 unw_debug("cfa_remember_state: ");
796                                 if (ptr.p8 == state->label) {
797                                         state->label = NULL;
798                                         return 1;
799                                 }
800                                 if (state->stackDepth >= MAX_STACK_DEPTH)
801                                         return 0;
802                                 state->stack[state->stackDepth++] = ptr.p8;
803                                 break;
804                         case DW_CFA_restore_state:
805                                 unw_debug("cfa_restore_state: ");
806                                 if (state->stackDepth) {
807                                         const uleb128_t loc = state->loc;
808                                         const u8 *label = state->label;
809 
810                                         state->label =
811                                             state->stack[state->stackDepth - 1];
812                                         memcpy(&state->cfa, &badCFA,
813                                                sizeof(state->cfa));
814                                         memset(state->regs, 0,
815                                                sizeof(state->regs));
816                                         state->stackDepth = 0;
817                                         result =
818                                             processCFI(start, end, 0, ptrType,
819                                                        state);
820                                         state->loc = loc;
821                                         state->label = label;
822                                 } else
823                                         return 0;
824                                 break;
825                         case DW_CFA_def_cfa:
826                                 state->cfa.reg = get_uleb128(&ptr.p8, end);
827                                 unw_debug("cfa_def_cfa: r%lu ", state->cfa.reg);
828                                 fallthrough;
829                         case DW_CFA_def_cfa_offset:
830                                 state->cfa.offs = get_uleb128(&ptr.p8, end);
831                                 unw_debug("cfa_def_cfa_offset: 0x%lx ",
832                                           state->cfa.offs);
833                                 break;
834                         case DW_CFA_def_cfa_sf:
835                                 state->cfa.reg = get_uleb128(&ptr.p8, end);
836                                 fallthrough;
837                         case DW_CFA_def_cfa_offset_sf:
838                                 state->cfa.offs = get_sleb128(&ptr.p8, end)
839                                     * state->dataAlign;
840                                 break;
841                         case DW_CFA_def_cfa_register:
842                                 unw_debug("cfa_def_cfa_register: ");
843                                 state->cfa.reg = get_uleb128(&ptr.p8, end);
844                                 break;
845                                 /*todo case DW_CFA_def_cfa_expression: */
846                                 /*todo case DW_CFA_expression: */
847                                 /*todo case DW_CFA_val_expression: */
848                         case DW_CFA_GNU_args_size:
849                                 get_uleb128(&ptr.p8, end);
850                                 break;
851                         case DW_CFA_GNU_negative_offset_extended:
852                                 value = get_uleb128(&ptr.p8, end);
853                                 set_rule(value,
854                                          Memory,
855                                          (uleb128_t) 0 - get_uleb128(&ptr.p8,
856                                                                      end),
857                                          state);
858                                 break;
859                         case DW_CFA_GNU_window_save:
860                         default:
861                                 unw_debug("UNKNOWN OPCODE 0x%x\n", opcode);
862                                 result = 0;
863                                 break;
864                         }
865                         break;
866                 case 1:
867                         unw_debug("\ncfa_adv_loc: ");
868                         result = advance_loc(*ptr.p8++ & 0x3f, state);
869                         break;
870                 case 2:
871                         unw_debug("cfa_offset: ");
872                         value = *ptr.p8++ & 0x3f;
873                         set_rule(value, Memory, get_uleb128(&ptr.p8, end),
874                                  state);
875                         break;
876                 case 3:
877                         unw_debug("cfa_restore: ");
878                         set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
879                         break;
880                 }
881 
882                 if (ptr.p8 > end)
883                         result = 0;
884                 if (result && targetLoc != 0 && targetLoc < state->loc)
885                         return 1;
886         }
887 
888         return result && ptr.p8 == end && (targetLoc == 0 || (
889                 /*todo While in theory this should apply, gcc in practice omits
890                   everything past the function prolog, and hence the location
891                   never reaches the end of the function.
892                 targetLoc < state->loc && */  state->label == NULL));
893 }
894 
895 /* Unwind to previous to frame.  Returns 0 if successful, negative
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[r].offs])
900         const u32 *fde = NULL, *cie = NULL;
901         const u8 *ptr = NULL, *end = NULL;
902         unsigned long pc = UNW_PC(frame) - frame->call_frame;
903         unsigned long startLoc = 0, endLoc = 0, cfa;
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: 0x%lx, FP: 0x%x\n",
914                   UNW_PC(frame), UNW_BLINK(frame), UNW_SP(frame),
915                   UNW_FP(frame));
916 
917         if (UNW_PC(frame) == 0)
918                 return -EINVAL;
919 
920 #ifdef UNWIND_DEBUG
921         {
922                 unsigned long *sptr = (unsigned long *)UNW_SP(frame);
923                 unw_debug("\nStack Dump:\n");
924                 for (i = 0; i < 20; i++, sptr++)
925                         unw_debug("0x%p:  0x%lx\n", sptr, *sptr);
926                 unw_debug("\n");
927         }
928 #endif
929 
930         table = find_table(pc);
931         if (table != NULL
932             && !(table->size & (sizeof(*fde) - 1))) {
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_PE_FORM) {
939                         case DW_EH_PE_native:
940                                 tableSize = sizeof(unsigned long);
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->hdrsz;
957                         if (tableSize && read_pointer(&ptr, end, hdr[1])
958                             == (unsigned long)table->address
959                             && (i = read_pointer(&ptr, end, hdr[2])) > 0
960                             && i == (end - ptr) / (2 * tableSize)
961                             && !((end - ptr) % (2 * tableSize))) {
962                                 do {
963                                         const u8 *cur =
964                                             ptr + (i / 2) * (2 * tableSize);
965 
966                                         startLoc = read_pointer(&cur,
967                                                                 cur + tableSize,
968                                                                 hdr[3]);
969                                         if (pc < startLoc)
970                                                 i /= 2;
971                                         else {
972                                                 ptr = cur - tableSize;
973                                                 i = (i + 1) / 2;
974                                         }
975                                 } while (startLoc && i > 1);
976                                 if (i == 1
977                                     && (startLoc = read_pointer(&ptr,
978                                                                 ptr + tableSize,
979                                                                 hdr[3])) != 0
980                                     && pc >= startLoc)
981                                         fde = (void *)read_pointer(&ptr,
982                                                                    ptr +
983                                                                    tableSize,
984                                                                    hdr[3]);
985                         }
986                 }
987 
988                 if (fde != NULL) {
989                         cie = cie_for_fde(fde, table);
990                         ptr = (const u8 *)(fde + 2);
991                         if (cie != NULL
992                             && cie != &bad_cie
993                             && cie != &not_fde
994                             && (ptrType = fde_pointer_type(cie)) >= 0
995                             && read_pointer(&ptr,
996                                             (const u8 *)(fde + 1) + *fde,
997                                             ptrType) == startLoc) {
998                                 if (!(ptrType & DW_EH_PE_indirect))
999                                         ptrType &=
1000                                             DW_EH_PE_FORM | DW_EH_PE_signed;
1001                                 endLoc =
1002                                     startLoc + read_pointer(&ptr,
1003                                                             (const u8 *)(fde +
1004                                                                          1) +
1005                                                             *fde, ptrType);
1006                                 if (pc >= endLoc) {
1007                                         fde = NULL;
1008                                         cie = NULL;
1009                                 }
1010                         } else {
1011                                 fde = NULL;
1012                                 cie = NULL;
1013                         }
1014                 }
1015         }
1016         if (cie != NULL) {
1017                 memset(&state, 0, sizeof(state));
1018                 state.cieEnd = ptr;     /* keep here temporarily */
1019                 ptr = (const u8 *)(cie + 2);
1020                 end = (const u8 *)(cie + 1) + *cie;
1021                 frame->call_frame = 1;
1022                 if (*++ptr) {
1023                         /* check if augmentation size is first (thus present) */
1024                         if (*ptr == 'z') {
1025                                 while (++ptr < end && *ptr) {
1026                                         switch (*ptr) {
1027                                         /* chk for ignorable or already handled
1028                                          * nul-terminated augmentation string */
1029                                         case 'L':
1030                                         case 'P':
1031                                         case 'R':
1032                                                 continue;
1033                                         case 'S':
1034                                                 frame->call_frame = 0;
1035                                                 continue;
1036                                         default:
1037                                                 break;
1038                                         }
1039                                         break;
1040                                 }
1041                         }
1042                         if (ptr >= end || *ptr)
1043                                 cie = NULL;
1044                 }
1045                 ++ptr;
1046         }
1047         if (cie != NULL) {
1048                 /* get code alignment factor */
1049                 state.codeAlign = get_uleb128(&ptr, end);
1050                 /* get data alignment factor */
1051                 state.dataAlign = get_sleb128(&ptr, end);
1052                 if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
1053                         cie = NULL;
1054                 else {
1055                         retAddrReg =
1056                             state.version <= 1 ? *ptr++ : get_uleb128(&ptr,
1057                                                                       end);
1058                         unw_debug("CIE Frame Info:\n");
1059                         unw_debug("return Address register 0x%lx\n",
1060                                   retAddrReg);
1061                         unw_debug("data Align: %ld\n", state.dataAlign);
1062                         unw_debug("code Align: %lu\n", state.codeAlign);
1063                         /* skip augmentation */
1064                         if (((const char *)(cie + 2))[1] == 'z') {
1065                                 uleb128_t augSize = get_uleb128(&ptr, end);
1066 
1067                                 ptr += augSize;
1068                         }
1069                         if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info)
1070                             || REG_INVALID(retAddrReg)
1071                             || reg_info[retAddrReg].width !=
1072                             sizeof(unsigned long))
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) + *fde;
1081                 /* skip augmentation */
1082                 if (((const char *)(cie + 2))[1] == 'z') {
1083                         uleb128_t augSize = get_uleb128(&ptr, end);
1084 
1085                         if ((ptr += augSize) > end)
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->task);
1094                 bottom = STACK_BOTTOM_UNW(frame->task);
1095 #if FRAME_RETADDR_OFFSET < 0
1096                 if (UNW_SP(frame) < top && UNW_FP(frame) <= UNW_SP(frame)
1097                     && bottom < UNW_FP(frame)
1098 #else
1099                 if (UNW_SP(frame) > top && UNW_FP(frame) >= UNW_SP(frame)
1100                     && bottom > UNW_FP(frame)
1101 #endif
1102                     && !((UNW_SP(frame) | UNW_FP(frame))
1103                          & (sizeof(unsigned long) - 1))) {
1104                         unsigned long link;
1105 
1106                         if (!__get_user(link, (unsigned long *)
1107                                         (UNW_FP(frame) + FRAME_LINK_OFFSET))
1108 #if FRAME_RETADDR_OFFSET < 0
1109                             && link > bottom && link < UNW_FP(frame)
1110 #else
1111                             && link > UNW_FP(frame) && link < bottom
1112 #endif
1113                             && !(link & (sizeof(link) - 1))
1114                             && !__get_user(UNW_PC(frame),
1115                                            (unsigned long *)(UNW_FP(frame)
1116                                                 + FRAME_RETADDR_OFFSET)))
1117                         {
1118                                 UNW_SP(frame) =
1119                                     UNW_FP(frame) + FRAME_RETADDR_OFFSET
1120 #if FRAME_RETADDR_OFFSET < 0
1121                                     -
1122 #else
1123                                     +
1124 #endif
1125                                     sizeof(UNW_PC(frame));
1126                                 UNW_FP(frame) = link;
1127                                 return 0;
1128                         }
1129                 }
1130 #endif
1131                 return -ENXIO;
1132         }
1133         state.org = startLoc;
1134         memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
1135 
1136         unw_debug("\nProcess instructions\n");
1137 
1138         /* process instructions
1139          * For ARC, we optimize by having blink(retAddrReg) with
1140          * the sameValue in the leaf function, so we should not check
1141          * state.regs[retAddrReg].where == Nowhere
1142          */
1143         if (!processCFI(ptr, end, pc, ptrType, &state)
1144             || state.loc > endLoc
1145 /*         || state.regs[retAddrReg].where == Nowhere */
1146             || state.cfa.reg >= ARRAY_SIZE(reg_info)
1147             || reg_info[state.cfa.reg].width != sizeof(unsigned long)
1148             || state.cfa.offs % sizeof(unsigned long))
1149                 return -EIO;
1150 
1151 #ifdef UNWIND_DEBUG
1152         unw_debug("\n");
1153 
1154         unw_debug("\nRegister State Based on the rules parsed from FDE:\n");
1155         for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
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(%lu),", i, state.regs[i].value);
1165                         break;
1166                 case Register:
1167                         unw_debug(" r%d: r(%lu),", i, state.regs[i].value);
1168                         break;
1169                 case Value:
1170                         unw_debug(" r%d: v(%lu),", i, state.regs[i].value);
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[retAddrReg], state.dataAlign))
1181                 frame->call_frame = 0;
1182         cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
1183         startLoc = min_t(unsigned long, UNW_SP(frame), cfa);
1184         endLoc = max_t(unsigned long, UNW_SP(frame), cfa);
1185         if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
1186                 startLoc = min(STACK_LIMIT(cfa), cfa);
1187                 endLoc = max(STACK_LIMIT(cfa), cfa);
1188         }
1189 
1190         unw_debug("\nCFA reg: 0x%lx, offset: 0x%lx =>  0x%lx\n",
1191                   state.cfa.reg, state.cfa.offs, cfa);
1192 
1193         for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1194                 if (REG_INVALID(i)) {
1195                         if (state.regs[i].where == Nowhere)
1196                                 continue;
1197                         return -EIO;
1198                 }
1199                 switch (state.regs[i].where) {
1200                 default:
1201                         break;
1202                 case Register:
1203                         if (state.regs[i].value >= ARRAY_SIZE(reg_info)
1204                             || REG_INVALID(state.regs[i].value)
1205                             || reg_info[i].width >
1206                             reg_info[state.regs[i].value].width)
1207                                 return -EIO;
1208                         switch (reg_info[state.regs[i].value].width) {
1209                         case sizeof(u8):
1210                                 state.regs[i].value =
1211                                 FRAME_REG(state.regs[i].value, const u8);
1212                                 break;
1213                         case sizeof(u16):
1214                                 state.regs[i].value =
1215                                 FRAME_REG(state.regs[i].value, const u16);
1216                                 break;
1217                         case sizeof(u32):
1218                                 state.regs[i].value =
1219                                 FRAME_REG(state.regs[i].value, const u32);
1220                                 break;
1221 #ifdef CONFIG_64BIT
1222                         case sizeof(u64):
1223                                 state.regs[i].value =
1224                                 FRAME_REG(state.regs[i].value, const u64);
1225                                 break;
1226 #endif
1227                         default:
1228                                 return -EIO;
1229                         }
1230                         break;
1231                 }
1232         }
1233 
1234         unw_debug("\nRegister state after evaluation with realtime Stack:\n");
1235         fptr = (unsigned long *)(&frame->regs);
1236         for (i = 0; i < ARRAY_SIZE(state.regs); ++i, fptr++) {
1237 
1238                 if (REG_INVALID(i))
1239                         continue;
1240                 switch (state.regs[i].where) {
1241                 case Nowhere:
1242                         if (reg_info[i].width != sizeof(UNW_SP(frame))
1243                             || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
1244                             != &UNW_SP(frame))
1245                                 continue;
1246                         UNW_SP(frame) = cfa;
1247                         break;
1248                 case Register:
1249                         switch (reg_info[i].width) {
1250                         case sizeof(u8):
1251                                 FRAME_REG(i, u8) = state.regs[i].value;
1252                                 break;
1253                         case sizeof(u16):
1254                                 FRAME_REG(i, u16) = state.regs[i].value;
1255                                 break;
1256                         case sizeof(u32):
1257                                 FRAME_REG(i, u32) = state.regs[i].value;
1258                                 break;
1259 #ifdef CONFIG_64BIT
1260                         case sizeof(u64):
1261                                 FRAME_REG(i, u64) = state.regs[i].value;
1262                                 break;
1263 #endif
1264                         default:
1265                                 return -EIO;
1266                         }
1267                         break;
1268                 case Value:
1269                         if (reg_info[i].width != sizeof(unsigned long))
1270                                 return -EIO;
1271                         FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
1272                             * state.dataAlign;
1273                         break;
1274                 case Memory:
1275                         addr = cfa + state.regs[i].value * state.dataAlign;
1276 
1277                         if ((state.regs[i].value * state.dataAlign)
1278                             % sizeof(unsigned long)
1279                             || addr < startLoc
1280                             || addr + sizeof(unsigned long) < addr
1281                             || addr + sizeof(unsigned long) > endLoc)
1282                                         return -EIO;
1283 
1284                         switch (reg_info[i].width) {
1285                         case sizeof(u8):
1286                                 __get_user(FRAME_REG(i, u8),
1287                                            (u8 __user *)addr);
1288                                 break;
1289                         case sizeof(u16):
1290                                 __get_user(FRAME_REG(i, u16),
1291                                            (u16 __user *)addr);
1292                                 break;
1293                         case sizeof(u32):
1294                                 __get_user(FRAME_REG(i, u32),
1295                                            (u32 __user *)addr);
1296                                 break;
1297 #ifdef CONFIG_64BIT
1298                         case sizeof(u64):
1299                                 __get_user(FRAME_REG(i, u64),
1300                                            (u64 __user *)addr);
1301                                 break;
1302 #endif
1303                         default:
1304                                 return -EIO;
1305                         }
1306 
1307                         break;
1308                 }
1309                 unw_debug("r%d: 0x%lx ", i, *fptr);
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