Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

objtool/LoongArch: Enable orc to be built

Implement arch-specific init_orc_entry(), write_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>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>

authored by

Tiezhu Yang and committed by
Huacai Chen
3c7266cd b8e85e6f

+250
+58
tools/arch/loongarch/include/asm/orc_types.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + #ifndef _ORC_TYPES_H 3 + #define _ORC_TYPES_H 4 + 5 + #include <linux/types.h> 6 + 7 + /* 8 + * The ORC_REG_* registers are base registers which are used to find other 9 + * registers on the stack. 10 + * 11 + * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the 12 + * address of the previous frame: the caller's SP before it called the current 13 + * function. 14 + * 15 + * ORC_REG_UNDEFINED means the corresponding register's value didn't change in 16 + * the current frame. 17 + * 18 + * The most commonly used base registers are SP and FP -- which the previous SP 19 + * is usually based on -- and PREV_SP and UNDEFINED -- which the previous FP is 20 + * usually based on. 21 + * 22 + * The rest of the base registers are needed for special cases like entry code 23 + * and GCC realigned stacks. 24 + */ 25 + #define ORC_REG_UNDEFINED 0 26 + #define ORC_REG_PREV_SP 1 27 + #define ORC_REG_SP 2 28 + #define ORC_REG_FP 3 29 + #define ORC_REG_MAX 4 30 + 31 + #define ORC_TYPE_UNDEFINED 0 32 + #define ORC_TYPE_END_OF_STACK 1 33 + #define ORC_TYPE_CALL 2 34 + #define ORC_TYPE_REGS 3 35 + #define ORC_TYPE_REGS_PARTIAL 4 36 + 37 + #ifndef __ASSEMBLY__ 38 + /* 39 + * This struct is more or less a vastly simplified version of the DWARF Call 40 + * Frame Information standard. It contains only the necessary parts of DWARF 41 + * CFI, simplified for ease of access by the in-kernel unwinder. It tells the 42 + * unwinder how to find the previous SP and FP (and sometimes entry regs) on 43 + * the stack for a given code address. Each instance of the struct corresponds 44 + * to one or more code locations. 45 + */ 46 + struct orc_entry { 47 + s16 sp_offset; 48 + s16 fp_offset; 49 + s16 ra_offset; 50 + unsigned int sp_reg:4; 51 + unsigned int fp_reg:4; 52 + unsigned int ra_reg:4; 53 + unsigned int type:3; 54 + unsigned int signal:1; 55 + }; 56 + #endif /* __ASSEMBLY__ */ 57 + 58 + #endif /* _ORC_TYPES_H */
+4
tools/objtool/Makefile
··· 57 57 BUILD_ORC := y 58 58 endif 59 59 60 + ifeq ($(SRCARCH),loongarch) 61 + BUILD_ORC := y 62 + endif 63 + 60 64 export BUILD_ORC 61 65 export srctree OUTPUT CFLAGS SRCARCH AWK 62 66 include $(srctree)/tools/build/Makefile.include
+1
tools/objtool/arch/loongarch/Build
··· 1 1 objtool-y += decode.o 2 2 objtool-y += special.o 3 + objtool-y += orc.o
+16
tools/objtool/arch/loongarch/decode.c
··· 3 3 #include <objtool/check.h> 4 4 #include <objtool/warn.h> 5 5 #include <asm/inst.h> 6 + #include <asm/orc_types.h> 7 + #include <linux/objtool_types.h> 6 8 7 9 #ifndef EM_LOONGARCH 8 10 #define EM_LOONGARCH 258 ··· 44 42 45 43 int arch_decode_hint_reg(u8 sp_reg, int *base) 46 44 { 45 + switch (sp_reg) { 46 + case ORC_REG_UNDEFINED: 47 + *base = CFI_UNDEFINED; 48 + break; 49 + case ORC_REG_SP: 50 + *base = CFI_SP; 51 + break; 52 + case ORC_REG_FP: 53 + *base = CFI_FP; 54 + break; 55 + default: 56 + return -1; 57 + } 58 + 47 59 return 0; 48 60 } 49 61
+171
tools/objtool/arch/loongarch/orc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + #include <linux/objtool_types.h> 3 + #include <asm/orc_types.h> 4 + 5 + #include <objtool/check.h> 6 + #include <objtool/orc.h> 7 + #include <objtool/warn.h> 8 + #include <objtool/endianness.h> 9 + 10 + int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn) 11 + { 12 + struct cfi_reg *fp = &cfi->regs[CFI_FP]; 13 + struct cfi_reg *ra = &cfi->regs[CFI_RA]; 14 + 15 + memset(orc, 0, sizeof(*orc)); 16 + 17 + if (!cfi) { 18 + /* 19 + * This is usually either unreachable nops/traps (which don't 20 + * trigger unreachable instruction warnings), or 21 + * STACK_FRAME_NON_STANDARD functions. 22 + */ 23 + orc->type = ORC_TYPE_UNDEFINED; 24 + return 0; 25 + } 26 + 27 + switch (cfi->type) { 28 + case UNWIND_HINT_TYPE_UNDEFINED: 29 + orc->type = ORC_TYPE_UNDEFINED; 30 + return 0; 31 + case UNWIND_HINT_TYPE_END_OF_STACK: 32 + orc->type = ORC_TYPE_END_OF_STACK; 33 + return 0; 34 + case UNWIND_HINT_TYPE_CALL: 35 + orc->type = ORC_TYPE_CALL; 36 + break; 37 + case UNWIND_HINT_TYPE_REGS: 38 + orc->type = ORC_TYPE_REGS; 39 + break; 40 + case UNWIND_HINT_TYPE_REGS_PARTIAL: 41 + orc->type = ORC_TYPE_REGS_PARTIAL; 42 + break; 43 + default: 44 + WARN_INSN(insn, "unknown unwind hint type %d", cfi->type); 45 + return -1; 46 + } 47 + 48 + orc->signal = cfi->signal; 49 + 50 + switch (cfi->cfa.base) { 51 + case CFI_SP: 52 + orc->sp_reg = ORC_REG_SP; 53 + break; 54 + case CFI_FP: 55 + orc->sp_reg = ORC_REG_FP; 56 + break; 57 + default: 58 + WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); 59 + return -1; 60 + } 61 + 62 + switch (fp->base) { 63 + case CFI_UNDEFINED: 64 + orc->fp_reg = ORC_REG_UNDEFINED; 65 + orc->fp_offset = 0; 66 + break; 67 + case CFI_CFA: 68 + orc->fp_reg = ORC_REG_PREV_SP; 69 + orc->fp_offset = fp->offset; 70 + break; 71 + case CFI_FP: 72 + orc->fp_reg = ORC_REG_FP; 73 + break; 74 + default: 75 + WARN_INSN(insn, "unknown FP base reg %d", fp->base); 76 + return -1; 77 + } 78 + 79 + switch (ra->base) { 80 + case CFI_UNDEFINED: 81 + orc->ra_reg = ORC_REG_UNDEFINED; 82 + orc->ra_offset = 0; 83 + break; 84 + case CFI_CFA: 85 + orc->ra_reg = ORC_REG_PREV_SP; 86 + orc->ra_offset = ra->offset; 87 + break; 88 + case CFI_FP: 89 + orc->ra_reg = ORC_REG_FP; 90 + break; 91 + default: 92 + WARN_INSN(insn, "unknown RA base reg %d", ra->base); 93 + return -1; 94 + } 95 + 96 + orc->sp_offset = cfi->cfa.offset; 97 + 98 + return 0; 99 + } 100 + 101 + int write_orc_entry(struct elf *elf, struct section *orc_sec, 102 + struct section *ip_sec, unsigned int idx, 103 + struct section *insn_sec, unsigned long insn_off, 104 + struct orc_entry *o) 105 + { 106 + struct orc_entry *orc; 107 + 108 + /* populate ORC data */ 109 + orc = (struct orc_entry *)orc_sec->data->d_buf + idx; 110 + memcpy(orc, o, sizeof(*orc)); 111 + 112 + /* populate reloc for ip */ 113 + if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, 114 + insn_sec, insn_off)) 115 + return -1; 116 + 117 + return 0; 118 + } 119 + 120 + static const char *reg_name(unsigned int reg) 121 + { 122 + switch (reg) { 123 + case ORC_REG_SP: 124 + return "sp"; 125 + case ORC_REG_FP: 126 + return "fp"; 127 + case ORC_REG_PREV_SP: 128 + return "prevsp"; 129 + default: 130 + return "?"; 131 + } 132 + } 133 + 134 + static const char *orc_type_name(unsigned int type) 135 + { 136 + switch (type) { 137 + case UNWIND_HINT_TYPE_CALL: 138 + return "call"; 139 + case UNWIND_HINT_TYPE_REGS: 140 + return "regs"; 141 + case UNWIND_HINT_TYPE_REGS_PARTIAL: 142 + return "regs (partial)"; 143 + default: 144 + return "?"; 145 + } 146 + } 147 + 148 + static void print_reg(unsigned int reg, int offset) 149 + { 150 + if (reg == ORC_REG_UNDEFINED) 151 + printf(" (und) "); 152 + else 153 + printf("%s + %3d", reg_name(reg), offset); 154 + 155 + } 156 + 157 + void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i) 158 + { 159 + printf("type:%s", orc_type_name(orc[i].type)); 160 + 161 + printf(" sp:"); 162 + print_reg(orc[i].sp_reg, orc[i].sp_offset); 163 + 164 + printf(" fp:"); 165 + print_reg(orc[i].fp_reg, orc[i].fp_offset); 166 + 167 + printf(" ra:"); 168 + print_reg(orc[i].ra_reg, orc[i].ra_offset); 169 + 170 + printf(" signal:%d\n", orc[i].signal); 171 + }