staticinlinebool scan_handlers(unsignedlong entry_offset)
{ int idx, offset;
if (entry_offset >= EXCCODE_INT_START * VECSIZE) returnfalse;
idx = entry_offset / VECSIZE;
offset = entry_offset % VECSIZE; switch (idx) { case EXCCODE_ADE: return offset == unwind_hint_ade; case EXCCODE_ALE: return offset == unwind_hint_ale; case EXCCODE_BP: return offset == unwind_hint_bp; case EXCCODE_FPE: return offset == unwind_hint_fpe; case EXCCODE_FPDIS: return offset == unwind_hint_fpu; case EXCCODE_LSXDIS: return offset == unwind_hint_lsx; case EXCCODE_LASXDIS: return offset == unwind_hint_lasx; case EXCCODE_BTDIS: return offset == unwind_hint_lbt; case EXCCODE_INE: return offset == unwind_hint_ri; case EXCCODE_WATCH: return offset == unwind_hint_watch; default: returnfalse;
}
}
staticinlinebool fix_exception(unsignedlong pc)
{ #ifdef CONFIG_NUMA int cpu;
for_each_possible_cpu(cpu) { if (!pcpu_handlers[cpu]) continue; if (scan_handlers(pc - pcpu_handlers[cpu])) returntrue;
} #endif return scan_handlers(pc - eentry);
}
/* * As we meet ftrace_regs_entry, reset first flag like first doing * tracing. Prologue analysis will stop soon because PC is at entry.
*/ staticinlinebool fix_ftrace(unsignedlong pc)
{ #ifdef CONFIG_DYNAMIC_FTRACE return pc == (unsignedlong)ftrace_call + LOONGARCH_INSN_SIZE; #else returnfalse; #endif
}
staticinlinebool unwind_state_fixup(struct unwind_state *state)
{ if (!fix_exception(state->pc) && !fix_ftrace(state->pc)) returnfalse;
state->reset = true; returntrue;
}
/* * LoongArch function prologue is like follows, * [instructions not use stack var] * addi.d sp, sp, -imm * st.d xx, sp, offset <- save callee saved regs and * st.d yy, sp, offset save ra if function is nest. * [others instructions]
*/ staticbool unwind_by_prologue(struct unwind_state *state)
{ long frame_ra = -1; unsignedlong frame_size = 0; unsignedlong size, offset, pc; struct pt_regs *regs; struct stack_info *info = &state->stack_info; union loongarch_instruction *ip, *ip_end;
if (state->sp >= info->end || state->sp < info->begin) returnfalse;
/* * When first is not set, the PC is a return address in the previous frame. * We need to adjust its value in case overflow to the next symbol.
*/
pc = state->pc - (state->first ? 0 : LOONGARCH_INSN_SIZE); if (!kallsyms_lookup_size_offset(pc, &size, &offset)) returnfalse;
while (ip < ip_end) { if (is_stack_alloc_ins(ip)) {
frame_size = (1 << 12) - ip->reg2i12_format.immediate;
ip++; break;
}
ip++;
}
/* * Can't find stack alloc action, PC may be in a leaf function. Only the * first being true is reasonable, otherwise indicate analysis is broken.
*/ if (!frame_size) { if (state->first) goto first;
returnfalse;
}
while (ip < ip_end) { if (is_ra_save_ins(ip)) {
frame_ra = ip->reg2i12_format.immediate; break;
} if (is_branch_ins(ip)) break;
ip++;
}
/* Can't find save $ra action, PC may be in a leaf function, too. */ if (frame_ra < 0) { if (state->first) {
state->sp = state->sp + frame_size; goto first;
} returnfalse;
}
/* * The current PC is not kernel text address, we cannot find its * relative symbol. Thus, prologue analysis will be broken. Luckily, * we can use the default_next_frame().
*/ if (!__kernel_text_address(state->pc)) {
state->type = UNWINDER_GUESS; if (!unwind_done(state))
unwind_next_frame(state);
}
}
EXPORT_SYMBOL_GPL(unwind_start);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.