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

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

Version: ~ [ linux-5.2-rc1 ] ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp