Messages in this thread | | | Subject | Re: [PATCH 2/3] LoongArch: Add prologue unwinder support | From | Jinyang He <> | Date | Fri, 29 Jul 2022 10:14:44 +0800 |
| |
Hi, Qing,
On 07/28/2022 10:05 PM, Qing Zhang wrote: > It unwind the stack frame based on prologue code analyze. > CONFIG_KALLSYMS is needed, at least the address and length > of each function. > > Three stages when we do unwind, > (1)unwind_start(), the prapare of unwinding, fill unwind_state. > (2)unwind_done(), judge whether the unwind process is finished or not. > (3)unwind_next_frame(), unwind the next frame. > > Dividing unwinder helps to add new unwinders in the future, eg: > unwind_frame, unwind_orc .etc > > Signed-off-by: Qing Zhang <zhangqing@loongson.cn> > > > +static inline bool is_stack_alloc_ins(union loongarch_instruction *ip) > +{ > + /* addi.d $sp, $sp, -imm */ > + return ip->reg2i12_format.opcode == addid_op && > + ip->reg2i12_format.rj == LOONGARCH_GPR_SP && > + ip->reg2i12_format.rd == LOONGARCH_GPR_SP && > + ip->reg2i12_format.immediate & (1 << 11); Checking the sign bit can be used in other place. > +} > + > +static inline bool is_ra_save_ins(union loongarch_instruction *ip) > +{ > + /* st.d $ra, $sp, offset */ > + return ip->reg2i12_format.opcode == std_op && > + ip->reg2i12_format.rj == LOONGARCH_GPR_SP && > + ip->reg2i12_format.rd == LOONGARCH_GPR_RA; > +} > + > +static inline bool is_branch_insn(union loongarch_instruction insn) Does it by using pointer parameter as above functions do. > +{ > + return insn.reg1i21_format.opcode >= beqz_op && > + insn.reg1i21_format.opcode <= bgeu_op; > +} > + > u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm); > u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm); > u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest); > diff --git a/arch/loongarch/include/asm/unwind.h b/arch/loongarch/include/asm/unwind.h > index 243330b39d0d..09394e536ea9 100644 > --- a/arch/loongarch/include/asm/unwind.h > +++ b/arch/loongarch/include/asm/unwind.h > @@ -14,6 +14,10 @@ > struct unwind_state { > struct stack_info stack_info; > struct task_struct *task; > +#if defined(CONFIG_UNWINDER_PROLOGUE) > + unsigned long ra; > + bool enable; Annotating here is appreciating. Enable is the way of prologue analysis while !enable is the way of guess. > +#endif > unsigned long sp, pc; > bool first; > bool error; [...] > + > +unsigned long unwind_get_return_address(struct unwind_state *state) > +{ > + > + if (unwind_done(state)) > + return 0; > + > + if (state->enable) > + return state->pc; > + else if (state->first) > + return state->pc; Combine conditions. > + > + return *(unsigned long *)(state->sp); > + > +} > +EXPORT_SYMBOL_GPL(unwind_get_return_address); > + > +static bool unwind_by_prologue(struct unwind_state *state) > +{ > + struct stack_info *info = &state->stack_info; > + union loongarch_instruction *ip, *ip_end; > + unsigned long frame_size = 0, frame_ra = -1; > + unsigned long size, offset, pc = state->pc; > + > + if (state->sp >= info->end || state->sp < info->begin) > + return false; > + > + if (!kallsyms_lookup_size_offset(pc, &size, &offset)) > + return false; > + > + ip = (union loongarch_instruction *)(pc - offset); > + ip_end = (union loongarch_instruction *)pc; > + > + while (ip < ip_end) { > + if (is_stack_alloc_ins(ip)) { > + frame_size = (1 << 12) - ip->reg2i12_format.immediate; Due to there will be other place convert unsigned to signed, we have a chance that create a inline function in inst.h. Do it as same as checking the sign bit.
> + ip++; > + break; > + } > + ip++; > + } > + [...] > + > + do { > + if (state->enable) { > + if (unwind_by_prologue(state)) > + return true; > + > + if (info->type == STACK_TYPE_IRQ && > + info->end == state->sp) { > + regs = (struct pt_regs *)info->next_sp; > + pc = regs->csr_era; > + if (user_mode(regs) || !__kernel_text_address(pc)) > + return false; > + > + state->pc = pc; > + state->sp = regs->regs[3]; > + state->ra = regs->regs[1]; > + state->first = true; > + get_stack_info(state->sp, state->task, info); > + > + return true; > + } > + } else { > + if (state->first) > + state->first = false; > + > + if (unwind_by_guess(state)) > + return true; > + } I'd prefer separate the block of 'if...else...' into two inline functions, that makes codes clear.
Thanks, Jinyang
| |