static int get_frame_info(struct mips_frame_info *info) { union mips_instruction *ip = info->func; int i, max_insns = min(128UL, info->func_size / sizeof(union mips_instruction)); info->pc_offset = -1; info->frame_size = 0; for (i = 0; i < max_insns; i++, ip++) { if (is_jal_jalr_jr_ins(ip)) break; if (!info->frame_size) { if (is_sp_move_ins(ip)) info->frame_size = - ip->i_format.simmediate; continue; } if (info->pc_offset == -1 && is_ra_save_ins(ip)) { info->pc_offset = ip->i_format.simmediate / sizeof(long); break; } } if (info->frame_size && info->pc_offset >= 0) /* nested */ return 0; if (info->pc_offset < 0) /* leaf */ return 1; /* prologue seems boggus... */ return -1; }
static inline int unwind_user_frame(struct stackframe *old_frame, const unsigned int max_instr_check) { struct stackframe new_frame = *old_frame; off_t ra_offset = 0; size_t stack_size = 0; unsigned long addr; if (old_frame->pc == 0 || old_frame->sp == 0 || old_frame->ra == 0) return -9; for (addr = new_frame.pc; (addr + max_instr_check > new_frame.pc) && (!ra_offset || !stack_size); --addr) { union mips_instruction ip; if (get_mem(addr, (unsigned long *) &ip)) return -11; if (is_sp_move_ins(&ip)) { int stack_adjustment = ip.i_format.simmediate; if (stack_adjustment > 0) /* This marks the end of the previous function, which means we overran. */ break; stack_size = (unsigned long) stack_adjustment; } else if (is_ra_save_ins(&ip)) { int ra_slot = ip.i_format.simmediate; if (ra_slot < 0) /* This shouldn't happen. */ break; ra_offset = ra_slot; } else if (is_end_of_function_marker(&ip)) break; } if (!ra_offset || !stack_size) goto done; if (ra_offset) { new_frame.ra = old_frame->sp + ra_offset; if (get_mem(new_frame.ra, &(new_frame.ra))) return -13; } if (stack_size) { new_frame.sp = old_frame->sp + stack_size; if (get_mem(new_frame.sp, &(new_frame.sp))) return -14; } if (new_frame.sp > old_frame->sp) return -2; done: new_frame.pc = old_frame->ra; *old_frame = new_frame; return 0; }
static int get_frame_info(struct mips_frame_info *info) { union mips_instruction *ip = info->func; unsigned max_insns = info->func_size / sizeof(union mips_instruction); unsigned i; info->pc_offset = -1; info->frame_size = 0; if (!ip) goto err; if (max_insns == 0) max_insns = 128U; /* */ max_insns = min(128U, max_insns); for (i = 0; i < max_insns; i++, ip++) { if (is_jal_jalr_jr_ins(ip)) break; if (!info->frame_size) { if (is_sp_move_ins(ip)) info->frame_size = - ip->i_format.simmediate; continue; } if (info->pc_offset == -1 && is_ra_save_ins(ip)) { info->pc_offset = ip->i_format.simmediate / sizeof(long); break; } } if (info->frame_size && info->pc_offset >= 0) /* */ return 0; if (info->pc_offset < 0) /* */ return 1; /* */ err: return -1; }