File Index
Files and directories
Sign in
FILE

unwind.c

File preview with syntax highlighting.

linux-6.19.14/arch/arc/kernel/unwind.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
   4 * Copyright (C) 2002-2006 Novell, Inc.
   5 *	Jan Beulich <jbeulich@novell.com>
   6 *
   7 * A simple API for unwinding kernel stacks.  This is used for
   8 * debugging and error reporting purposes.  The kernel doesn't need
   9 * full-blown stack unwinding with all the bells and whistles, so there
  10 * is not much point in implementing the full Dwarf2 unwind API.
  11 */
  12
  13#include <linux/sched.h>
  14#include <linux/module.h>
  15#include <linux/memblock.h>
  16#include <linux/sort.h>
  17#include <linux/slab.h>
  18#include <linux/stop_machine.h>
  19#include <linux/uaccess.h>
  20#include <linux/ptrace.h>
  21#include <asm/sections.h>
  22#include <linux/unaligned.h>
  23#include <asm/unwind.h>
  24
  25extern 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
  31int dbg_unw;
  32#define unw_debug(fmt, ...)			\
  33do {						\
  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
  52static const struct {
  53	unsigned offs:BITS_PER_LONG / 2;
  54	unsigned width:BITS_PER_LONG / 2;
  55} reg_info[] = {
  56UNW_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
 113typedef unsigned long uleb128_t;
 114typedef signed long sleb128_t;
 115
 116static 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
 129struct unwind_item {
 130	enum item_location {
 131		Nowhere,
 132		Memory,
 133		Register,
 134		Value
 135	} where;
 136	uleb128_t value;
 137};
 138
 139struct 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
 154static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
 155
 156static 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
 170static unsigned long read_pointer(const u8 **pLoc,
 171				  const void *end, signed ptrType);
 172static 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 */
 179static void *__init unw_hdr_alloc_early(unsigned long sz)
 180{
 181	return memblock_alloc_from(sz, sizeof(unsigned int), MAX_DMA_ADDRESS);
 182}
 183
 184static 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
 217void __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
 227static const u32 bad_cie, not_fde;
 228static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *);
 229static const u32 *__cie_for_fde(const u32 *fde);
 230static signed fde_pointer_type(const u32 *cie);
 231
 232struct eh_frame_hdr_table_entry {
 233	unsigned long start, fde;
 234};
 235
 236static 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
 244static 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
 346ret_err:
 347	panic("Attention !!! Dwarf FDE parsing errors\n");
 348}
 349
 350#ifdef CONFIG_MODULES
 351static void *unw_hdr_alloc(unsigned long sz)
 352{
 353	return kmalloc(sz, GFP_KERNEL);
 354}
 355
 356static struct unwind_table *last_table;
 357
 358/* Must be called with module_mutex held. */
 359void *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
 394struct unlink_table_info {
 395	struct unwind_table *table;
 396	int init_only;
 397};
 398
 399static 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. */
 425void 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
 449static 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
 470static 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
 493static 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
 502static 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
 525static 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
 597static 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
 653static 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
 664static 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
 693static 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. */
 888int 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}
1306EXPORT_SYMBOL(arc_unwind);
~/ Read-only file preview.