Enscript Output

extractedLnx/linux-2.6.19/kernel/unwind.c_unwind.c

int unwind(struct unwind_frame_info *frame)
{
#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
	const u32 *fde = NULL, *cie = NULL;
	const u8 *ptr = NULL, *end = NULL;
	unsigned long pc = UNW_PC(frame) - frame->call_frame;
	unsigned long startLoc = 0, endLoc = 0, cfa;
	unsigned i;
	signed ptrType = -1;
	uleb128_t retAddrReg = 0;
	const struct unwind_table *table;
	struct unwind_state state;

	if (UNW_PC(frame) == 0)
		return -EINVAL;
	if ((table = find_table(pc)) != NULL
	    && !(table->size & (sizeof(*fde) - 1))) {
		const u8 *hdr = table->header;
		unsigned long tableSize;

		smp_rmb();
		if (hdr && hdr[0] == 1) {
			switch(hdr[3] & DW_EH_PE_FORM) {
			case DW_EH_PE_native: tableSize = sizeof(unsigned long); break;
			case DW_EH_PE_data2: tableSize = 2; break;
			case DW_EH_PE_data4: tableSize = 4; break;
			case DW_EH_PE_data8: tableSize = 8; break;
			default: tableSize = 0; break;
			}
			ptr = hdr + 4;
			end = hdr + table->hdrsz;
			if (tableSize
			    && read_pointer(&ptr, end, hdr[1])
			       == (unsigned long)table->address
			    && (i = read_pointer(&ptr, end, hdr[2])) > 0
			    && i == (end - ptr) / (2 * tableSize)
			    && !((end - ptr) % (2 * tableSize))) {
				do {
					const u8 *cur = ptr + (i / 2) * (2 * tableSize);

					startLoc = read_pointer(&cur,
					                        cur + tableSize,
					                        hdr[3]);
					if (pc < startLoc)
						i /= 2;
					else {
						ptr = cur - tableSize;
						i = (i + 1) / 2;
					}
				} while (startLoc && i > 1);
				if (i == 1
				    && (startLoc = read_pointer(&ptr,
				                                ptr + tableSize,
				                                hdr[3])) != 0
				    && pc >= startLoc)
					fde = (void *)read_pointer(&ptr,
					                           ptr + tableSize,
					                           hdr[3]);
			}
		}

		if (fde != NULL) {
			cie = cie_for_fde(fde, table);
			ptr = (const u8 *)(fde + 2);
			if(cie != NULL
			   && cie != &bad_cie
			   && cie != &not_fde
			   && (ptrType = fde_pointer_type(cie)) >= 0
			   && read_pointer(&ptr,
			                   (const u8 *)(fde + 1) + *fde,
			                   ptrType) == startLoc) {
				if (!(ptrType & DW_EH_PE_indirect))
					ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed;
				endLoc = startLoc
				         + read_pointer(&ptr,
				                        (const u8 *)(fde + 1) + *fde,
				                        ptrType);
				if(pc >= endLoc)
					fde = NULL;
			} else
				fde = NULL;
		}
		if (fde == NULL) {
			for (fde = table->address, tableSize = table->size;
			     cie = NULL, tableSize > sizeof(*fde)
			     && tableSize - sizeof(*fde) >= *fde;
			     tableSize -= sizeof(*fde) + *fde,
			     fde += 1 + *fde / sizeof(*fde)) {
				cie = cie_for_fde(fde, table);
				if (cie == &bad_cie) {
					cie = NULL;
					break;
				}
				if (cie == NULL
				    || cie == &not_fde
				    || (ptrType = fde_pointer_type(cie)) < 0)
					continue;
				ptr = (const u8 *)(fde + 2);
				startLoc = read_pointer(&ptr,
				                        (const u8 *)(fde + 1) + *fde,
				                        ptrType);
				if (!startLoc)
					continue;
				if (!(ptrType & DW_EH_PE_indirect))
					ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed;
				endLoc = startLoc
				         + read_pointer(&ptr,
				                        (const u8 *)(fde + 1) + *fde,
				                        ptrType);
				if (pc >= startLoc && pc < endLoc)
					break;
			}
		}
	}
	if (cie != NULL) {
		memset(&state, 0, sizeof(state));
		state.cieEnd = ptr; /* keep here temporarily */
		ptr = (const u8 *)(cie + 2);
		end = (const u8 *)(cie + 1) + *cie;
		frame->call_frame = 1;
		if ((state.version = *ptr) != 1)
			cie = NULL; /* unsupported version */
		else if (*++ptr) {
			/* check if augmentation size is first (and thus present) */
			if (*ptr == 'z') {
				while (++ptr < end && *ptr) {
					switch(*ptr) {
					/* check for ignorable (or already handled)
					 * nul-terminated augmentation string */
					case 'L':
					case 'P':
					case 'R':
						continue;
					case 'S':
						frame->call_frame = 0;
						continue;
					default:
						break;
					}
					break;
				}
			}
			if (ptr >= end || *ptr)
				cie = NULL;
		}
		++ptr;
	}
	if (cie != NULL) {
		/* get code aligment factor */
		state.codeAlign = get_uleb128(&ptr, end);
		/* get data aligment factor */
		state.dataAlign = get_sleb128(&ptr, end);
		if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
			cie = NULL;
		else {
			retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end);
			/* skip augmentation */
			if (((const char *)(cie + 2))[1] == 'z') {
				uleb128_t augSize = get_uleb128(&ptr, end);

				ptr += augSize;
			}
			if (ptr > end
			   || retAddrReg >= ARRAY_SIZE(reg_info)
			   || REG_INVALID(retAddrReg)
			   || reg_info[retAddrReg].width != sizeof(unsigned long))
				cie = NULL;
		}
	}
	if (cie != NULL) {
		state.cieStart = ptr;
		ptr = state.cieEnd;
		state.cieEnd = end;
		end = (const u8 *)(fde + 1) + *fde;
		/* skip augmentation */
		if (((const char *)(cie + 2))[1] == 'z') {
			uleb128_t augSize = get_uleb128(&ptr, end);

			if ((ptr += augSize) > end)
				fde = NULL;
		}
	}
	if (cie == NULL || fde == NULL) {
#ifdef CONFIG_FRAME_POINTER
		unsigned long top, bottom;

		top = STACK_TOP(frame->task);
		bottom = STACK_BOTTOM(frame->task);
# if FRAME_RETADDR_OFFSET < 0
		if (UNW_SP(frame) < top
		    && UNW_FP(frame) <= UNW_SP(frame)
		    && bottom < UNW_FP(frame)
# else
		if (UNW_SP(frame) > top
		    && UNW_FP(frame) >= UNW_SP(frame)
		    && bottom > UNW_FP(frame)
# endif
		   && !((UNW_SP(frame) | UNW_FP(frame))
		        & (sizeof(unsigned long) - 1))) {
			unsigned long link;

			if (!__get_user(link,
			                (unsigned long *)(UNW_FP(frame)
			                                  + FRAME_LINK_OFFSET))
# if FRAME_RETADDR_OFFSET < 0
			   && link > bottom && link < UNW_FP(frame)
# else
			   && link > UNW_FP(frame) && link < bottom
# endif
			   && !(link & (sizeof(link) - 1))
			   && !__get_user(UNW_PC(frame),
			                  (unsigned long *)(UNW_FP(frame)
			                                    + FRAME_RETADDR_OFFSET))) {
				UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET
# if FRAME_RETADDR_OFFSET < 0
					-
# else
					+
# endif
					  sizeof(UNW_PC(frame));
				UNW_FP(frame) = link;
				return 0;
			}
		}
#endif
		return -ENXIO;
	}
	state.org = startLoc;
	memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
	/* process instructions */
	if (!processCFI(ptr, end, pc, ptrType, &state)
	   || state.loc > endLoc
	   || state.regs[retAddrReg].where == Nowhere
	   || state.cfa.reg >= ARRAY_SIZE(reg_info)
	   || reg_info[state.cfa.reg].width != sizeof(unsigned long)
	   || state.cfa.offs % sizeof(unsigned long))
		return -EIO;
	/* update frame */
#ifndef CONFIG_AS_CFI_SIGNAL_FRAME
	if(frame->call_frame
	   && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
		frame->call_frame = 0;
#endif
	cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
	startLoc = min((unsigned long)UNW_SP(frame), cfa);
	endLoc = max((unsigned long)UNW_SP(frame), cfa);
	if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
		startLoc = min(STACK_LIMIT(cfa), cfa);
		endLoc = max(STACK_LIMIT(cfa), cfa);
	}
#ifndef CONFIG_64BIT
# define CASES CASE(8); CASE(16); CASE(32)
#else
# define CASES CASE(8); CASE(16); CASE(32); CASE(64)
#endif
	for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
		if (REG_INVALID(i)) {
			if (state.regs[i].where == Nowhere)
				continue;
			return -EIO;
		}
		switch(state.regs[i].where) {
		default:
			break;
		case Register:
			if (state.regs[i].value >= ARRAY_SIZE(reg_info)
			   || REG_INVALID(state.regs[i].value)
			   || reg_info[i].width > reg_info[state.regs[i].value].width)
				return -EIO;
			switch(reg_info[state.regs[i].value].width) {
#define CASE(n) \
			case sizeof(u##n): \
				state.regs[i].value = FRAME_REG(state.regs[i].value, \
				                                const u##n); \
				break
			CASES;
#undef CASE
			default:
				return -EIO;
			}
			break;
		}
	}
	for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
		if (REG_INVALID(i))
			continue;
		switch(state.regs[i].where) {
		case Nowhere:
			if (reg_info[i].width != sizeof(UNW_SP(frame))
			   || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
			      != &UNW_SP(frame))
				continue;
			UNW_SP(frame) = cfa;
			break;
		case Register:
			switch(reg_info[i].width) {
#define CASE(n) case sizeof(u##n): \
				FRAME_REG(i, u##n) = state.regs[i].value; \
				break
			CASES;
#undef CASE
			default:
				return -EIO;
			}
			break;
		case Value:
			if (reg_info[i].width != sizeof(unsigned long))
				return -EIO;
			FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
			                                    * state.dataAlign;
			break;
		case Memory: {
				unsigned long addr = cfa + state.regs[i].value
				                           * state.dataAlign;

				if ((state.regs[i].value * state.dataAlign)
				    % sizeof(unsigned long)
				    || addr < startLoc
				    || addr + sizeof(unsigned long) < addr
				    || addr + sizeof(unsigned long) > endLoc)
					return -EIO;
				switch(reg_info[i].width) {
#define CASE(n)     case sizeof(u##n): \
					__get_user(FRAME_REG(i, u##n), (u##n *)addr); \
					break
				CASES;
#undef CASE
				default:
					return -EIO;
				}
			}
			break;
		}
	}

	return 0;
#undef CASES
#undef FRAME_REG
}

Generated by GNU enscript 1.6.4.