Messages in this thread | | | From | Huacai Chen <> | Date | Tue, 10 Oct 2023 20:52:41 +0800 | Subject | Re: [PATCH v2 4/8] objtool/LoongArch: Enable orc to be built |
| |
Hi, Tiezhu,
On Mon, Oct 9, 2023 at 9:03 PM Tiezhu Yang <yangtiezhu@loongson.cn> wrote: > > Implement arch-specific init_orc_entry(), reg_name(), orc_type_name(), > print_reg() and orc_print_dump(), then set BUILD_ORC as y to build the > orc related files. > > Co-developed-by: Jinyang He <hejinyang@loongson.cn> > Signed-off-by: Jinyang He <hejinyang@loongson.cn> > Co-developed-by: Youling Tang <tangyouling@loongson.cn> > Signed-off-by: Youling Tang <tangyouling@loongson.cn> > Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn> > --- > tools/arch/loongarch/include/asm/orc_types.h | 58 ++++++++++ > tools/objtool/Makefile | 4 + > tools/objtool/arch/loongarch/Build | 1 + > tools/objtool/arch/loongarch/decode.c | 16 +++ > tools/objtool/arch/loongarch/orc.c | 155 +++++++++++++++++++++++++++ > 5 files changed, 234 insertions(+) > create mode 100644 tools/arch/loongarch/include/asm/orc_types.h > create mode 100644 tools/objtool/arch/loongarch/orc.c > > diff --git a/tools/arch/loongarch/include/asm/orc_types.h b/tools/arch/loongarch/include/asm/orc_types.h > new file mode 100644 > index 0000000..1d37e62 > --- /dev/null > +++ b/tools/arch/loongarch/include/asm/orc_types.h > @@ -0,0 +1,58 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +#ifndef _ORC_TYPES_H > +#define _ORC_TYPES_H > + > +#include <linux/types.h> > + > +/* > + * The ORC_REG_* registers are base registers which are used to find other > + * registers on the stack. > + * > + * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the > + * address of the previous frame: the caller's SP before it called the current > + * function. > + * > + * ORC_REG_UNDEFINED means the corresponding register's value didn't change in > + * the current frame. > + * > + * The most commonly used base registers are SP and BP -- which the previous SP > + * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is > + * usually based on. > + * > + * The rest of the base registers are needed for special cases like entry code > + * and GCC realigned stacks. > + */ > +#define ORC_REG_UNDEFINED 0 > +#define ORC_REG_PREV_SP 1 > +#define ORC_REG_SP 2 > +#define ORC_REG_BP 3 There is no BP register for LoongArch, so I think all 'BP' should be 'FP' in this patch.
Huacai
> +#define ORC_REG_MAX 4 > + > +#define ORC_TYPE_UNDEFINED 0 > +#define ORC_TYPE_END_OF_STACK 1 > +#define ORC_TYPE_CALL 2 > +#define ORC_TYPE_REGS 3 > +#define ORC_TYPE_REGS_PARTIAL 4 > + > +#ifndef __ASSEMBLY__ > +/* > + * This struct is more or less a vastly simplified version of the DWARF Call > + * Frame Information standard. It contains only the necessary parts of DWARF > + * CFI, simplified for ease of access by the in-kernel unwinder. It tells the > + * unwinder how to find the previous SP and BP (and sometimes entry regs) on > + * the stack for a given code address. Each instance of the struct corresponds > + * to one or more code locations. > + */ > +struct orc_entry { > + s16 sp_offset; > + s16 bp_offset; > + s16 ra_offset; > + unsigned int sp_reg:4; > + unsigned int bp_reg:4; > + unsigned int ra_reg:4; > + unsigned int type:3; > + unsigned int signal:1; > +}; > +#endif /* __ASSEMBLY__ */ > + > +#endif /* _ORC_TYPES_H */ > diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile > index 83b100c..bf7f7f8 100644 > --- a/tools/objtool/Makefile > +++ b/tools/objtool/Makefile > @@ -57,6 +57,10 @@ ifeq ($(SRCARCH),x86) > BUILD_ORC := y > endif > > +ifeq ($(SRCARCH),loongarch) > + BUILD_ORC := y > +endif > + > export BUILD_ORC > export srctree OUTPUT CFLAGS SRCARCH AWK > include $(srctree)/tools/build/Makefile.include > diff --git a/tools/objtool/arch/loongarch/Build b/tools/objtool/arch/loongarch/Build > index d24d563..1d4b784 100644 > --- a/tools/objtool/arch/loongarch/Build > +++ b/tools/objtool/arch/loongarch/Build > @@ -1,2 +1,3 @@ > objtool-y += decode.o > objtool-y += special.o > +objtool-y += orc.o > diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loongarch/decode.c > index 3a426e4..1c96759 100644 > --- a/tools/objtool/arch/loongarch/decode.c > +++ b/tools/objtool/arch/loongarch/decode.c > @@ -3,6 +3,8 @@ > #include <objtool/check.h> > #include <objtool/warn.h> > #include <asm/inst.h> > +#include <asm/orc_types.h> > +#include <linux/objtool_types.h> > > int arch_ftrace_match(char *name) > { > @@ -38,6 +40,20 @@ bool arch_callee_saved_reg(unsigned char reg) > > int arch_decode_hint_reg(u8 sp_reg, int *base) > { > + switch (sp_reg) { > + case ORC_REG_UNDEFINED: > + *base = CFI_UNDEFINED; > + break; > + case ORC_REG_SP: > + *base = CFI_SP; > + break; > + case ORC_REG_BP: > + *base = CFI_FP; > + break; > + default: > + return -1; > + } > + > return 0; > } > > diff --git a/tools/objtool/arch/loongarch/orc.c b/tools/objtool/arch/loongarch/orc.c > new file mode 100644 > index 0000000..7d7ecee > --- /dev/null > +++ b/tools/objtool/arch/loongarch/orc.c > @@ -0,0 +1,155 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +#include <linux/objtool_types.h> > +#include <asm/orc_types.h> > + > +#include <objtool/check.h> > +#include <objtool/orc.h> > +#include <objtool/warn.h> > +#include <objtool/endianness.h> > + > +int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn) > +{ > + struct cfi_reg *bp = &cfi->regs[CFI_BP]; > + struct cfi_reg *ra = &cfi->regs[CFI_RA]; > + > + memset(orc, 0, sizeof(*orc)); > + > + if (!cfi) { > + /* > + * This is usually either unreachable nops/traps (which don't > + * trigger unreachable instruction warnings), or > + * STACK_FRAME_NON_STANDARD functions. > + */ > + orc->type = ORC_TYPE_UNDEFINED; > + return 0; > + } > + > + switch (cfi->type) { > + case UNWIND_HINT_TYPE_UNDEFINED: > + orc->type = ORC_TYPE_UNDEFINED; > + return 0; > + case UNWIND_HINT_TYPE_END_OF_STACK: > + orc->type = ORC_TYPE_END_OF_STACK; > + return 0; > + case UNWIND_HINT_TYPE_CALL: > + orc->type = ORC_TYPE_CALL; > + break; > + case UNWIND_HINT_TYPE_REGS: > + orc->type = ORC_TYPE_REGS; > + break; > + case UNWIND_HINT_TYPE_REGS_PARTIAL: > + orc->type = ORC_TYPE_REGS_PARTIAL; > + break; > + default: > + WARN_INSN(insn, "unknown unwind hint type %d", cfi->type); > + return -1; > + } > + > + orc->signal = cfi->signal; > + > + switch (cfi->cfa.base) { > + case CFI_SP: > + orc->sp_reg = ORC_REG_SP; > + break; > + case CFI_BP: > + orc->sp_reg = ORC_REG_BP; > + break; > + default: > + WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); > + return -1; > + } > + > + switch (bp->base) { > + case CFI_UNDEFINED: > + orc->bp_reg = ORC_REG_UNDEFINED; > + orc->bp_offset = 0; > + break; > + case CFI_CFA: > + orc->bp_reg = ORC_REG_PREV_SP; > + orc->bp_offset = bp->offset; > + break; > + case CFI_BP: > + orc->bp_reg = ORC_REG_BP; > + break; > + default: > + WARN_INSN(insn, "unknown BP base reg %d", bp->base); > + return -1; > + } > + > + switch (ra->base) { > + case CFI_UNDEFINED: > + orc->ra_reg = ORC_REG_UNDEFINED; > + orc->ra_offset = 0; > + break; > + case CFI_CFA: > + orc->ra_reg = ORC_REG_PREV_SP; > + orc->ra_offset = ra->offset; > + break; > + case CFI_BP: > + orc->ra_reg = ORC_REG_BP; > + break; > + default: > + WARN_INSN(insn, "unknown RA base reg %d", ra->base); > + return -1; > + } > + > + orc->sp_offset = cfi->cfa.offset; > + > + return 0; > +} > + > +static const char *reg_name(unsigned int reg) > +{ > + switch (reg) { > + case ORC_REG_SP: > + return "sp"; > + case ORC_REG_BP: > + return "fp"; > + case ORC_REG_PREV_SP: > + return "prevsp"; > + default: > + return "?"; > + } > +} > + > +static const char *orc_type_name(unsigned int type) > +{ > + switch (type) { > + case UNWIND_HINT_TYPE_CALL: > + return "call"; > + case UNWIND_HINT_TYPE_REGS: > + return "regs"; > + case UNWIND_HINT_TYPE_REGS_PARTIAL: > + return "regs (partial)"; > + default: > + return "?"; > + } > +} > + > +static void print_reg(unsigned int reg, int offset) > +{ > + if (reg == ORC_REG_UNDEFINED) > + printf(" (und) "); > + else > + printf("%s + %3d", reg_name(reg), offset); > + > +} > + > +void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i) > +{ > + printf("type:%s", orc_type_name(orc[i].type)); > + > + printf(" sp:"); > + > + print_reg(orc[i].sp_reg, bswap_if_needed(dummy_elf, orc[i].sp_offset)); > + > + printf(" bp:"); > + > + print_reg(orc[i].bp_reg, bswap_if_needed(dummy_elf, orc[i].bp_offset)); > + > + printf(" ra:"); > + > + print_reg(orc[i].ra_reg, bswap_if_needed(dummy_elf, orc[i].ra_offset)); > + > + printf(" signal:%d\n", orc[i].signal); > +} > -- > 2.1.0 >
| |