Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arc/kernel/unwind.c
26424 views
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 <[email protected]>
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 <linux/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 init_unwind_hdr(struct unwind_table *table,
245
void *(*alloc) (unsigned long))
246
{
247
const u8 *ptr;
248
unsigned long tableSize = table->size, hdrSize;
249
unsigned int n;
250
const u32 *fde;
251
struct {
252
u8 version;
253
u8 eh_frame_ptr_enc;
254
u8 fde_count_enc;
255
u8 table_enc;
256
unsigned long eh_frame_ptr;
257
unsigned int fde_count;
258
struct eh_frame_hdr_table_entry table[];
259
} __attribute__ ((__packed__)) *header;
260
261
if (table->header)
262
return;
263
264
if (table->hdrsz)
265
pr_warn(".eh_frame_hdr for '%s' present but unusable\n",
266
table->name);
267
268
if (tableSize & (sizeof(*fde) - 1))
269
return;
270
271
for (fde = table->address, n = 0;
272
tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
273
tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
274
const u32 *cie = cie_for_fde(fde, table);
275
signed ptrType;
276
277
if (cie == &not_fde)
278
continue;
279
if (cie == NULL || cie == &bad_cie)
280
goto ret_err;
281
ptrType = fde_pointer_type(cie);
282
if (ptrType < 0)
283
goto ret_err;
284
285
ptr = (const u8 *)(fde + 2);
286
if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde,
287
ptrType)) {
288
/* FIXME_Rajesh We have 4 instances of null addresses
289
* instead of the initial loc addr
290
* return;
291
*/
292
WARN(1, "unwinder: FDE->initial_location NULL %p\n",
293
(const u8 *)(fde + 1) + *fde);
294
}
295
++n;
296
}
297
298
if (tableSize || !n)
299
goto ret_err;
300
301
hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
302
+ 2 * n * sizeof(unsigned long);
303
304
header = alloc(hdrSize);
305
if (!header)
306
goto ret_err;
307
308
header->version = 1;
309
header->eh_frame_ptr_enc = DW_EH_PE_abs | DW_EH_PE_native;
310
header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4;
311
header->table_enc = DW_EH_PE_abs | DW_EH_PE_native;
312
put_unaligned((unsigned long)table->address, &header->eh_frame_ptr);
313
BUILD_BUG_ON(offsetof(typeof(*header), fde_count)
314
% __alignof(typeof(header->fde_count)));
315
header->fde_count = n;
316
317
BUILD_BUG_ON(offsetof(typeof(*header), table)
318
% __alignof(typeof(*header->table)));
319
for (fde = table->address, tableSize = table->size, n = 0;
320
tableSize;
321
tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
322
const u32 *cie = __cie_for_fde(fde);
323
324
if (fde[1] == CIE_ID)
325
continue; /* this is a CIE */
326
ptr = (const u8 *)(fde + 2);
327
header->table[n].start = read_pointer(&ptr,
328
(const u8 *)(fde + 1) +
329
*fde,
330
fde_pointer_type(cie));
331
header->table[n].fde = (unsigned long)fde;
332
++n;
333
}
334
WARN_ON(n != header->fde_count);
335
336
sort(header->table,
337
n,
338
sizeof(*header->table),
339
cmp_eh_frame_hdr_table_entries, NULL);
340
341
table->hdrsz = hdrSize;
342
smp_wmb();
343
table->header = (const void *)header;
344
return;
345
346
ret_err:
347
panic("Attention !!! Dwarf FDE parsing errors\n");
348
}
349
350
#ifdef CONFIG_MODULES
351
static void *unw_hdr_alloc(unsigned long sz)
352
{
353
return kmalloc(sz, GFP_KERNEL);
354
}
355
356
static struct unwind_table *last_table;
357
358
/* Must be called with module_mutex held. */
359
void *unwind_add_table(struct module *module, const void *table_start,
360
unsigned long table_size)
361
{
362
struct unwind_table *table;
363
struct module_memory *core_text;
364
struct module_memory *init_text;
365
366
if (table_size <= 0)
367
return NULL;
368
369
table = kmalloc(sizeof(*table), GFP_KERNEL);
370
if (!table)
371
return NULL;
372
373
core_text = &module->mem[MOD_TEXT];
374
init_text = &module->mem[MOD_INIT_TEXT];
375
376
init_unwind_table(table, module->name, core_text->base, core_text->size,
377
init_text->base, init_text->size, table_start, table_size, NULL, 0);
378
379
init_unwind_hdr(table, unw_hdr_alloc);
380
381
#ifdef UNWIND_DEBUG
382
unw_debug("Table added for [%s] %lx %lx\n",
383
module->name, table->core.pc, table->core.range);
384
#endif
385
if (last_table)
386
last_table->link = table;
387
else
388
root_table.link = table;
389
last_table = table;
390
391
return table;
392
}
393
394
struct unlink_table_info {
395
struct unwind_table *table;
396
int init_only;
397
};
398
399
static int unlink_table(void *arg)
400
{
401
struct unlink_table_info *info = arg;
402
struct unwind_table *table = info->table, *prev;
403
404
for (prev = &root_table; prev->link && prev->link != table;
405
prev = prev->link)
406
;
407
408
if (prev->link) {
409
if (info->init_only) {
410
table->init.pc = 0;
411
table->init.range = 0;
412
info->table = NULL;
413
} else {
414
prev->link = table->link;
415
if (!prev->link)
416
last_table = prev;
417
}
418
} else
419
info->table = NULL;
420
421
return 0;
422
}
423
424
/* Must be called with module_mutex held. */
425
void unwind_remove_table(void *handle, int init_only)
426
{
427
struct unwind_table *table = handle;
428
struct unlink_table_info info;
429
430
if (!table || table == &root_table)
431
return;
432
433
if (init_only && table == last_table) {
434
table->init.pc = 0;
435
table->init.range = 0;
436
return;
437
}
438
439
info.table = table;
440
info.init_only = init_only;
441
442
unlink_table(&info); /* XXX: SMP */
443
kfree(table->header);
444
kfree(table);
445
}
446
447
#endif /* CONFIG_MODULES */
448
449
static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
450
{
451
const u8 *cur = *pcur;
452
uleb128_t value;
453
unsigned int shift;
454
455
for (shift = 0, value = 0; cur < end; shift += 7) {
456
if (shift + 7 > 8 * sizeof(value)
457
&& (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
458
cur = end + 1;
459
break;
460
}
461
value |= (uleb128_t) (*cur & 0x7f) << shift;
462
if (!(*cur++ & 0x80))
463
break;
464
}
465
*pcur = cur;
466
467
return value;
468
}
469
470
static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
471
{
472
const u8 *cur = *pcur;
473
sleb128_t value;
474
unsigned int shift;
475
476
for (shift = 0, value = 0; cur < end; shift += 7) {
477
if (shift + 7 > 8 * sizeof(value)
478
&& (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
479
cur = end + 1;
480
break;
481
}
482
value |= (sleb128_t) (*cur & 0x7f) << shift;
483
if (!(*cur & 0x80)) {
484
value |= -(*cur++ & 0x40) << shift;
485
break;
486
}
487
}
488
*pcur = cur;
489
490
return value;
491
}
492
493
static const u32 *__cie_for_fde(const u32 *fde)
494
{
495
const u32 *cie;
496
497
cie = fde + 1 - fde[1] / sizeof(*fde);
498
499
return cie;
500
}
501
502
static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table)
503
{
504
const u32 *cie;
505
506
if (!*fde || (*fde & (sizeof(*fde) - 1)))
507
return &bad_cie;
508
509
if (fde[1] == CIE_ID)
510
return &not_fde; /* this is a CIE */
511
512
if ((fde[1] & (sizeof(*fde) - 1)))
513
/* || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address) */
514
return NULL; /* this is not a valid FDE */
515
516
cie = __cie_for_fde(fde);
517
518
if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde)
519
|| (*cie & (sizeof(*cie) - 1))
520
|| (cie[1] != CIE_ID))
521
return NULL; /* this is not a (valid) CIE */
522
return cie;
523
}
524
525
static unsigned long read_pointer(const u8 **pLoc, const void *end,
526
signed ptrType)
527
{
528
unsigned long value = 0;
529
union {
530
const u8 *p8;
531
const u16 *p16u;
532
const s16 *p16s;
533
const u32 *p32u;
534
const s32 *p32s;
535
const unsigned long *pul;
536
} ptr;
537
538
if (ptrType < 0 || ptrType == DW_EH_PE_omit)
539
return 0;
540
ptr.p8 = *pLoc;
541
switch (ptrType & DW_EH_PE_FORM) {
542
case DW_EH_PE_data2:
543
if (end < (const void *)(ptr.p16u + 1))
544
return 0;
545
if (ptrType & DW_EH_PE_signed)
546
value = get_unaligned((u16 *) ptr.p16s++);
547
else
548
value = get_unaligned((u16 *) ptr.p16u++);
549
break;
550
case DW_EH_PE_data4:
551
#ifdef CONFIG_64BIT
552
if (end < (const void *)(ptr.p32u + 1))
553
return 0;
554
if (ptrType & DW_EH_PE_signed)
555
value = get_unaligned(ptr.p32s++);
556
else
557
value = get_unaligned(ptr.p32u++);
558
break;
559
case DW_EH_PE_data8:
560
BUILD_BUG_ON(sizeof(u64) != sizeof(value));
561
#else
562
BUILD_BUG_ON(sizeof(u32) != sizeof(value));
563
#endif
564
fallthrough;
565
case DW_EH_PE_native:
566
if (end < (const void *)(ptr.pul + 1))
567
return 0;
568
value = get_unaligned((unsigned long *)ptr.pul++);
569
break;
570
case DW_EH_PE_leb128:
571
BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
572
value = ptrType & DW_EH_PE_signed ? get_sleb128(&ptr.p8, end)
573
: get_uleb128(&ptr.p8, end);
574
if ((const void *)ptr.p8 > end)
575
return 0;
576
break;
577
default:
578
return 0;
579
}
580
switch (ptrType & DW_EH_PE_ADJUST) {
581
case DW_EH_PE_abs:
582
break;
583
case DW_EH_PE_pcrel:
584
value += (unsigned long)*pLoc;
585
break;
586
default:
587
return 0;
588
}
589
if ((ptrType & DW_EH_PE_indirect)
590
&& __get_user(value, (unsigned long __user *)value))
591
return 0;
592
*pLoc = ptr.p8;
593
594
return value;
595
}
596
597
static signed fde_pointer_type(const u32 *cie)
598
{
599
const u8 *ptr = (const u8 *)(cie + 2);
600
unsigned int version = *ptr;
601
602
if (*++ptr) {
603
const char *aug;
604
const u8 *end = (const u8 *)(cie + 1) + *cie;
605
uleb128_t len;
606
607
/* check if augmentation size is first (and thus present) */
608
if (*ptr != 'z')
609
return -1;
610
611
/* check if augmentation string is nul-terminated */
612
aug = (const void *)ptr;
613
ptr = memchr(aug, 0, end - ptr);
614
if (ptr == NULL)
615
return -1;
616
617
++ptr; /* skip terminator */
618
get_uleb128(&ptr, end); /* skip code alignment */
619
get_sleb128(&ptr, end); /* skip data alignment */
620
/* skip return address column */
621
version <= 1 ? (void) ++ptr : (void)get_uleb128(&ptr, end);
622
len = get_uleb128(&ptr, end); /* augmentation length */
623
624
if (ptr + len < ptr || ptr + len > end)
625
return -1;
626
627
end = ptr + len;
628
while (*++aug) {
629
if (ptr >= end)
630
return -1;
631
switch (*aug) {
632
case 'L':
633
++ptr;
634
break;
635
case 'P':{
636
signed ptrType = *ptr++;
637
638
if (!read_pointer(&ptr, end, ptrType)
639
|| ptr > end)
640
return -1;
641
}
642
break;
643
case 'R':
644
return *ptr;
645
default:
646
return -1;
647
}
648
}
649
}
650
return DW_EH_PE_native | DW_EH_PE_abs;
651
}
652
653
static int advance_loc(unsigned long delta, struct unwind_state *state)
654
{
655
state->loc += delta * state->codeAlign;
656
657
/* FIXME_Rajesh: Probably we are defining for the initial range as well;
658
return delta > 0;
659
*/
660
unw_debug("delta %3lu => loc 0x%lx: ", delta, state->loc);
661
return 1;
662
}
663
664
static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value,
665
struct unwind_state *state)
666
{
667
if (reg < ARRAY_SIZE(state->regs)) {
668
state->regs[reg].where = where;
669
state->regs[reg].value = value;
670
671
#ifdef UNWIND_DEBUG
672
unw_debug("r%lu: ", reg);
673
switch (where) {
674
case Nowhere:
675
unw_debug("s ");
676
break;
677
case Memory:
678
unw_debug("c(%lu) ", value);
679
break;
680
case Register:
681
unw_debug("r(%lu) ", value);
682
break;
683
case Value:
684
unw_debug("v(%lu) ", value);
685
break;
686
default:
687
break;
688
}
689
#endif
690
}
691
}
692
693
static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc,
694
signed ptrType, struct unwind_state *state)
695
{
696
union {
697
const u8 *p8;
698
const u16 *p16;
699
const u32 *p32;
700
} ptr;
701
int result = 1;
702
u8 opcode;
703
704
if (start != state->cieStart) {
705
state->loc = state->org;
706
result =
707
processCFI(state->cieStart, state->cieEnd, 0, ptrType,
708
state);
709
if (targetLoc == 0 && state->label == NULL)
710
return result;
711
}
712
for (ptr.p8 = start; result && ptr.p8 < end;) {
713
switch (*ptr.p8 >> 6) {
714
uleb128_t value;
715
716
case 0:
717
opcode = *ptr.p8++;
718
719
switch (opcode) {
720
case DW_CFA_nop:
721
unw_debug("cfa nop ");
722
break;
723
case DW_CFA_set_loc:
724
state->loc = read_pointer(&ptr.p8, end,
725
ptrType);
726
if (state->loc == 0)
727
result = 0;
728
unw_debug("cfa_set_loc: 0x%lx ", state->loc);
729
break;
730
case DW_CFA_advance_loc1:
731
unw_debug("\ncfa advance loc1:");
732
result = ptr.p8 < end
733
&& advance_loc(*ptr.p8++, state);
734
break;
735
case DW_CFA_advance_loc2:
736
value = *ptr.p8++;
737
value += *ptr.p8++ << 8;
738
unw_debug("\ncfa advance loc2:");
739
result = ptr.p8 <= end + 2
740
/* && advance_loc(*ptr.p16++, state); */
741
&& advance_loc(value, state);
742
break;
743
case DW_CFA_advance_loc4:
744
unw_debug("\ncfa advance loc4:");
745
result = ptr.p8 <= end + 4
746
&& advance_loc(*ptr.p32++, state);
747
break;
748
case DW_CFA_offset_extended:
749
value = get_uleb128(&ptr.p8, end);
750
unw_debug("cfa_offset_extended: ");
751
set_rule(value, Memory,
752
get_uleb128(&ptr.p8, end), state);
753
break;
754
case DW_CFA_val_offset:
755
value = get_uleb128(&ptr.p8, end);
756
set_rule(value, Value,
757
get_uleb128(&ptr.p8, end), state);
758
break;
759
case DW_CFA_offset_extended_sf:
760
value = get_uleb128(&ptr.p8, end);
761
set_rule(value, Memory,
762
get_sleb128(&ptr.p8, end), state);
763
break;
764
case DW_CFA_val_offset_sf:
765
value = get_uleb128(&ptr.p8, end);
766
set_rule(value, Value,
767
get_sleb128(&ptr.p8, end), state);
768
break;
769
case DW_CFA_restore_extended:
770
unw_debug("cfa_restore_extended: ");
771
case DW_CFA_undefined:
772
unw_debug("cfa_undefined: ");
773
case DW_CFA_same_value:
774
unw_debug("cfa_same_value: ");
775
set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0,
776
state);
777
break;
778
case DW_CFA_register:
779
unw_debug("cfa_register: ");
780
value = get_uleb128(&ptr.p8, end);
781
set_rule(value,
782
Register,
783
get_uleb128(&ptr.p8, end), state);
784
break;
785
case DW_CFA_remember_state:
786
unw_debug("cfa_remember_state: ");
787
if (ptr.p8 == state->label) {
788
state->label = NULL;
789
return 1;
790
}
791
if (state->stackDepth >= MAX_STACK_DEPTH)
792
return 0;
793
state->stack[state->stackDepth++] = ptr.p8;
794
break;
795
case DW_CFA_restore_state:
796
unw_debug("cfa_restore_state: ");
797
if (state->stackDepth) {
798
const uleb128_t loc = state->loc;
799
const u8 *label = state->label;
800
801
state->label =
802
state->stack[state->stackDepth - 1];
803
memcpy(&state->cfa, &badCFA,
804
sizeof(state->cfa));
805
memset(state->regs, 0,
806
sizeof(state->regs));
807
state->stackDepth = 0;
808
result =
809
processCFI(start, end, 0, ptrType,
810
state);
811
state->loc = loc;
812
state->label = label;
813
} else
814
return 0;
815
break;
816
case DW_CFA_def_cfa:
817
state->cfa.reg = get_uleb128(&ptr.p8, end);
818
unw_debug("cfa_def_cfa: r%lu ", state->cfa.reg);
819
fallthrough;
820
case DW_CFA_def_cfa_offset:
821
state->cfa.offs = get_uleb128(&ptr.p8, end);
822
unw_debug("cfa_def_cfa_offset: 0x%lx ",
823
state->cfa.offs);
824
break;
825
case DW_CFA_def_cfa_sf:
826
state->cfa.reg = get_uleb128(&ptr.p8, end);
827
fallthrough;
828
case DW_CFA_def_cfa_offset_sf:
829
state->cfa.offs = get_sleb128(&ptr.p8, end)
830
* state->dataAlign;
831
break;
832
case DW_CFA_def_cfa_register:
833
unw_debug("cfa_def_cfa_register: ");
834
state->cfa.reg = get_uleb128(&ptr.p8, end);
835
break;
836
/*todo case DW_CFA_def_cfa_expression: */
837
/*todo case DW_CFA_expression: */
838
/*todo case DW_CFA_val_expression: */
839
case DW_CFA_GNU_args_size:
840
get_uleb128(&ptr.p8, end);
841
break;
842
case DW_CFA_GNU_negative_offset_extended:
843
value = get_uleb128(&ptr.p8, end);
844
set_rule(value,
845
Memory,
846
(uleb128_t) 0 - get_uleb128(&ptr.p8,
847
end),
848
state);
849
break;
850
case DW_CFA_GNU_window_save:
851
default:
852
unw_debug("UNKNOWN OPCODE 0x%x\n", opcode);
853
result = 0;
854
break;
855
}
856
break;
857
case 1:
858
unw_debug("\ncfa_adv_loc: ");
859
result = advance_loc(*ptr.p8++ & 0x3f, state);
860
break;
861
case 2:
862
unw_debug("cfa_offset: ");
863
value = *ptr.p8++ & 0x3f;
864
set_rule(value, Memory, get_uleb128(&ptr.p8, end),
865
state);
866
break;
867
case 3:
868
unw_debug("cfa_restore: ");
869
set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
870
break;
871
}
872
873
if (ptr.p8 > end)
874
result = 0;
875
if (result && targetLoc != 0 && targetLoc < state->loc)
876
return 1;
877
}
878
879
return result && ptr.p8 == end && (targetLoc == 0 || (
880
/*todo While in theory this should apply, gcc in practice omits
881
everything past the function prolog, and hence the location
882
never reaches the end of the function.
883
targetLoc < state->loc && */ state->label == NULL));
884
}
885
886
/* Unwind to previous to frame. Returns 0 if successful, negative
887
* number in case of an error. */
888
int arc_unwind(struct unwind_frame_info *frame)
889
{
890
#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
891
const u32 *fde = NULL, *cie = NULL;
892
const u8 *ptr = NULL, *end = NULL;
893
unsigned long pc = UNW_PC(frame) - frame->call_frame;
894
unsigned long startLoc = 0, endLoc = 0, cfa;
895
unsigned int i;
896
signed ptrType = -1;
897
uleb128_t retAddrReg = 0;
898
const struct unwind_table *table;
899
struct unwind_state state;
900
unsigned long *fptr;
901
unsigned long addr;
902
903
unw_debug("\n\nUNWIND FRAME:\n");
904
unw_debug("PC: 0x%lx BLINK: 0x%lx, SP: 0x%lx, FP: 0x%x\n",
905
UNW_PC(frame), UNW_BLINK(frame), UNW_SP(frame),
906
UNW_FP(frame));
907
908
if (UNW_PC(frame) == 0)
909
return -EINVAL;
910
911
#ifdef UNWIND_DEBUG
912
{
913
unsigned long *sptr = (unsigned long *)UNW_SP(frame);
914
unw_debug("\nStack Dump:\n");
915
for (i = 0; i < 20; i++, sptr++)
916
unw_debug("0x%p: 0x%lx\n", sptr, *sptr);
917
unw_debug("\n");
918
}
919
#endif
920
921
table = find_table(pc);
922
if (table != NULL
923
&& !(table->size & (sizeof(*fde) - 1))) {
924
const u8 *hdr = table->header;
925
unsigned long tableSize;
926
927
smp_rmb();
928
if (hdr && hdr[0] == 1) {
929
switch (hdr[3] & DW_EH_PE_FORM) {
930
case DW_EH_PE_native:
931
tableSize = sizeof(unsigned long);
932
break;
933
case DW_EH_PE_data2:
934
tableSize = 2;
935
break;
936
case DW_EH_PE_data4:
937
tableSize = 4;
938
break;
939
case DW_EH_PE_data8:
940
tableSize = 8;
941
break;
942
default:
943
tableSize = 0;
944
break;
945
}
946
ptr = hdr + 4;
947
end = hdr + table->hdrsz;
948
if (tableSize && read_pointer(&ptr, end, hdr[1])
949
== (unsigned long)table->address
950
&& (i = read_pointer(&ptr, end, hdr[2])) > 0
951
&& i == (end - ptr) / (2 * tableSize)
952
&& !((end - ptr) % (2 * tableSize))) {
953
do {
954
const u8 *cur =
955
ptr + (i / 2) * (2 * tableSize);
956
957
startLoc = read_pointer(&cur,
958
cur + tableSize,
959
hdr[3]);
960
if (pc < startLoc)
961
i /= 2;
962
else {
963
ptr = cur - tableSize;
964
i = (i + 1) / 2;
965
}
966
} while (startLoc && i > 1);
967
if (i == 1
968
&& (startLoc = read_pointer(&ptr,
969
ptr + tableSize,
970
hdr[3])) != 0
971
&& pc >= startLoc)
972
fde = (void *)read_pointer(&ptr,
973
ptr +
974
tableSize,
975
hdr[3]);
976
}
977
}
978
979
if (fde != NULL) {
980
cie = cie_for_fde(fde, table);
981
ptr = (const u8 *)(fde + 2);
982
if (cie != NULL
983
&& cie != &bad_cie
984
&& cie != &not_fde
985
&& (ptrType = fde_pointer_type(cie)) >= 0
986
&& read_pointer(&ptr,
987
(const u8 *)(fde + 1) + *fde,
988
ptrType) == startLoc) {
989
if (!(ptrType & DW_EH_PE_indirect))
990
ptrType &=
991
DW_EH_PE_FORM | DW_EH_PE_signed;
992
endLoc =
993
startLoc + read_pointer(&ptr,
994
(const u8 *)(fde +
995
1) +
996
*fde, ptrType);
997
if (pc >= endLoc) {
998
fde = NULL;
999
cie = NULL;
1000
}
1001
} else {
1002
fde = NULL;
1003
cie = NULL;
1004
}
1005
}
1006
}
1007
if (cie != NULL) {
1008
memset(&state, 0, sizeof(state));
1009
state.cieEnd = ptr; /* keep here temporarily */
1010
ptr = (const u8 *)(cie + 2);
1011
end = (const u8 *)(cie + 1) + *cie;
1012
frame->call_frame = 1;
1013
if (*++ptr) {
1014
/* check if augmentation size is first (thus present) */
1015
if (*ptr == 'z') {
1016
while (++ptr < end && *ptr) {
1017
switch (*ptr) {
1018
/* chk for ignorable or already handled
1019
* nul-terminated augmentation string */
1020
case 'L':
1021
case 'P':
1022
case 'R':
1023
continue;
1024
case 'S':
1025
frame->call_frame = 0;
1026
continue;
1027
default:
1028
break;
1029
}
1030
break;
1031
}
1032
}
1033
if (ptr >= end || *ptr)
1034
cie = NULL;
1035
}
1036
++ptr;
1037
}
1038
if (cie != NULL) {
1039
/* get code alignment factor */
1040
state.codeAlign = get_uleb128(&ptr, end);
1041
/* get data alignment factor */
1042
state.dataAlign = get_sleb128(&ptr, end);
1043
if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
1044
cie = NULL;
1045
else {
1046
retAddrReg =
1047
state.version <= 1 ? *ptr++ : get_uleb128(&ptr,
1048
end);
1049
unw_debug("CIE Frame Info:\n");
1050
unw_debug("return Address register 0x%lx\n",
1051
retAddrReg);
1052
unw_debug("data Align: %ld\n", state.dataAlign);
1053
unw_debug("code Align: %lu\n", state.codeAlign);
1054
/* skip augmentation */
1055
if (((const char *)(cie + 2))[1] == 'z') {
1056
uleb128_t augSize = get_uleb128(&ptr, end);
1057
1058
ptr += augSize;
1059
}
1060
if (ptr > end || retAddrReg >= ARRAY_SIZE(reg_info)
1061
|| REG_INVALID(retAddrReg)
1062
|| reg_info[retAddrReg].width !=
1063
sizeof(unsigned long))
1064
cie = NULL;
1065
}
1066
}
1067
if (cie != NULL) {
1068
state.cieStart = ptr;
1069
ptr = state.cieEnd;
1070
state.cieEnd = end;
1071
end = (const u8 *)(fde + 1) + *fde;
1072
/* skip augmentation */
1073
if (((const char *)(cie + 2))[1] == 'z') {
1074
uleb128_t augSize = get_uleb128(&ptr, end);
1075
1076
if ((ptr += augSize) > end)
1077
fde = NULL;
1078
}
1079
}
1080
if (cie == NULL || fde == NULL) {
1081
#ifdef CONFIG_FRAME_POINTER
1082
unsigned long top, bottom;
1083
1084
top = STACK_TOP_UNW(frame->task);
1085
bottom = STACK_BOTTOM_UNW(frame->task);
1086
#if FRAME_RETADDR_OFFSET < 0
1087
if (UNW_SP(frame) < top && UNW_FP(frame) <= UNW_SP(frame)
1088
&& bottom < UNW_FP(frame)
1089
#else
1090
if (UNW_SP(frame) > top && UNW_FP(frame) >= UNW_SP(frame)
1091
&& bottom > UNW_FP(frame)
1092
#endif
1093
&& !((UNW_SP(frame) | UNW_FP(frame))
1094
& (sizeof(unsigned long) - 1))) {
1095
unsigned long link;
1096
1097
if (!__get_user(link, (unsigned long *)
1098
(UNW_FP(frame) + FRAME_LINK_OFFSET))
1099
#if FRAME_RETADDR_OFFSET < 0
1100
&& link > bottom && link < UNW_FP(frame)
1101
#else
1102
&& link > UNW_FP(frame) && link < bottom
1103
#endif
1104
&& !(link & (sizeof(link) - 1))
1105
&& !__get_user(UNW_PC(frame),
1106
(unsigned long *)(UNW_FP(frame)
1107
+ FRAME_RETADDR_OFFSET)))
1108
{
1109
UNW_SP(frame) =
1110
UNW_FP(frame) + FRAME_RETADDR_OFFSET
1111
#if FRAME_RETADDR_OFFSET < 0
1112
-
1113
#else
1114
+
1115
#endif
1116
sizeof(UNW_PC(frame));
1117
UNW_FP(frame) = link;
1118
return 0;
1119
}
1120
}
1121
#endif
1122
return -ENXIO;
1123
}
1124
state.org = startLoc;
1125
memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
1126
1127
unw_debug("\nProcess instructions\n");
1128
1129
/* process instructions
1130
* For ARC, we optimize by having blink(retAddrReg) with
1131
* the sameValue in the leaf function, so we should not check
1132
* state.regs[retAddrReg].where == Nowhere
1133
*/
1134
if (!processCFI(ptr, end, pc, ptrType, &state)
1135
|| state.loc > endLoc
1136
/* || state.regs[retAddrReg].where == Nowhere */
1137
|| state.cfa.reg >= ARRAY_SIZE(reg_info)
1138
|| reg_info[state.cfa.reg].width != sizeof(unsigned long)
1139
|| state.cfa.offs % sizeof(unsigned long))
1140
return -EIO;
1141
1142
#ifdef UNWIND_DEBUG
1143
unw_debug("\n");
1144
1145
unw_debug("\nRegister State Based on the rules parsed from FDE:\n");
1146
for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1147
1148
if (REG_INVALID(i))
1149
continue;
1150
1151
switch (state.regs[i].where) {
1152
case Nowhere:
1153
break;
1154
case Memory:
1155
unw_debug(" r%d: c(%lu),", i, state.regs[i].value);
1156
break;
1157
case Register:
1158
unw_debug(" r%d: r(%lu),", i, state.regs[i].value);
1159
break;
1160
case Value:
1161
unw_debug(" r%d: v(%lu),", i, state.regs[i].value);
1162
break;
1163
}
1164
}
1165
1166
unw_debug("\n");
1167
#endif
1168
1169
/* update frame */
1170
if (frame->call_frame
1171
&& !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
1172
frame->call_frame = 0;
1173
cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
1174
startLoc = min_t(unsigned long, UNW_SP(frame), cfa);
1175
endLoc = max_t(unsigned long, UNW_SP(frame), cfa);
1176
if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
1177
startLoc = min(STACK_LIMIT(cfa), cfa);
1178
endLoc = max(STACK_LIMIT(cfa), cfa);
1179
}
1180
1181
unw_debug("\nCFA reg: 0x%lx, offset: 0x%lx => 0x%lx\n",
1182
state.cfa.reg, state.cfa.offs, cfa);
1183
1184
for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
1185
if (REG_INVALID(i)) {
1186
if (state.regs[i].where == Nowhere)
1187
continue;
1188
return -EIO;
1189
}
1190
switch (state.regs[i].where) {
1191
default:
1192
break;
1193
case Register:
1194
if (state.regs[i].value >= ARRAY_SIZE(reg_info)
1195
|| REG_INVALID(state.regs[i].value)
1196
|| reg_info[i].width >
1197
reg_info[state.regs[i].value].width)
1198
return -EIO;
1199
switch (reg_info[state.regs[i].value].width) {
1200
case sizeof(u8):
1201
state.regs[i].value =
1202
FRAME_REG(state.regs[i].value, const u8);
1203
break;
1204
case sizeof(u16):
1205
state.regs[i].value =
1206
FRAME_REG(state.regs[i].value, const u16);
1207
break;
1208
case sizeof(u32):
1209
state.regs[i].value =
1210
FRAME_REG(state.regs[i].value, const u32);
1211
break;
1212
#ifdef CONFIG_64BIT
1213
case sizeof(u64):
1214
state.regs[i].value =
1215
FRAME_REG(state.regs[i].value, const u64);
1216
break;
1217
#endif
1218
default:
1219
return -EIO;
1220
}
1221
break;
1222
}
1223
}
1224
1225
unw_debug("\nRegister state after evaluation with realtime Stack:\n");
1226
fptr = (unsigned long *)(&frame->regs);
1227
for (i = 0; i < ARRAY_SIZE(state.regs); ++i, fptr++) {
1228
1229
if (REG_INVALID(i))
1230
continue;
1231
switch (state.regs[i].where) {
1232
case Nowhere:
1233
if (reg_info[i].width != sizeof(UNW_SP(frame))
1234
|| &FRAME_REG(i, __typeof__(UNW_SP(frame)))
1235
!= &UNW_SP(frame))
1236
continue;
1237
UNW_SP(frame) = cfa;
1238
break;
1239
case Register:
1240
switch (reg_info[i].width) {
1241
case sizeof(u8):
1242
FRAME_REG(i, u8) = state.regs[i].value;
1243
break;
1244
case sizeof(u16):
1245
FRAME_REG(i, u16) = state.regs[i].value;
1246
break;
1247
case sizeof(u32):
1248
FRAME_REG(i, u32) = state.regs[i].value;
1249
break;
1250
#ifdef CONFIG_64BIT
1251
case sizeof(u64):
1252
FRAME_REG(i, u64) = state.regs[i].value;
1253
break;
1254
#endif
1255
default:
1256
return -EIO;
1257
}
1258
break;
1259
case Value:
1260
if (reg_info[i].width != sizeof(unsigned long))
1261
return -EIO;
1262
FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
1263
* state.dataAlign;
1264
break;
1265
case Memory:
1266
addr = cfa + state.regs[i].value * state.dataAlign;
1267
1268
if ((state.regs[i].value * state.dataAlign)
1269
% sizeof(unsigned long)
1270
|| addr < startLoc
1271
|| addr + sizeof(unsigned long) < addr
1272
|| addr + sizeof(unsigned long) > endLoc)
1273
return -EIO;
1274
1275
switch (reg_info[i].width) {
1276
case sizeof(u8):
1277
__get_user(FRAME_REG(i, u8),
1278
(u8 __user *)addr);
1279
break;
1280
case sizeof(u16):
1281
__get_user(FRAME_REG(i, u16),
1282
(u16 __user *)addr);
1283
break;
1284
case sizeof(u32):
1285
__get_user(FRAME_REG(i, u32),
1286
(u32 __user *)addr);
1287
break;
1288
#ifdef CONFIG_64BIT
1289
case sizeof(u64):
1290
__get_user(FRAME_REG(i, u64),
1291
(u64 __user *)addr);
1292
break;
1293
#endif
1294
default:
1295
return -EIO;
1296
}
1297
1298
break;
1299
}
1300
unw_debug("r%d: 0x%lx ", i, *fptr);
1301
}
1302
1303
return 0;
1304
#undef FRAME_REG
1305
}
1306
EXPORT_SYMBOL(arc_unwind);
1307
1308