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 9 int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn) 10 { 11 struct cfi_reg *fp = &cfi->regs[CFI_FP]; 12 struct cfi_reg *ra = &cfi->regs[CFI_RA]; 13 14 memset(orc, 0, sizeof(*orc)); 15 16 if (!cfi) { 17 /* 18 * This is usually either unreachable nops/traps (which don't 19 * trigger unreachable instruction warnings), or 20 * STACK_FRAME_NON_STANDARD functions. 21 */ 22 orc->type = ORC_TYPE_UNDEFINED; 23 return 0; 24 } 25 26 switch (cfi->type) { 27 case UNWIND_HINT_TYPE_UNDEFINED: 28 orc->type = ORC_TYPE_UNDEFINED; 29 return 0; 30 case UNWIND_HINT_TYPE_END_OF_STACK: 31 orc->type = ORC_TYPE_END_OF_STACK; 32 return 0; 33 case UNWIND_HINT_TYPE_CALL: 34 orc->type = ORC_TYPE_CALL; 35 break; 36 case UNWIND_HINT_TYPE_REGS: 37 orc->type = ORC_TYPE_REGS; 38 break; 39 case UNWIND_HINT_TYPE_REGS_PARTIAL: 40 orc->type = ORC_TYPE_REGS_PARTIAL; 41 break; 42 default: 43 ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type); 44 return -1; 45 } 46 47 orc->signal = cfi->signal; 48 49 switch (cfi->cfa.base) { 50 case CFI_SP: 51 orc->sp_reg = ORC_REG_SP; 52 break; 53 case CFI_FP: 54 orc->sp_reg = ORC_REG_FP; 55 break; 56 default: 57 ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); 58 return -1; 59 } 60 61 switch (fp->base) { 62 case CFI_UNDEFINED: 63 orc->fp_reg = ORC_REG_UNDEFINED; 64 orc->fp_offset = 0; 65 break; 66 case CFI_CFA: 67 orc->fp_reg = ORC_REG_PREV_SP; 68 orc->fp_offset = fp->offset; 69 break; 70 case CFI_FP: 71 orc->fp_reg = ORC_REG_FP; 72 break; 73 default: 74 ERROR_INSN(insn, "unknown FP base reg %d", fp->base); 75 return -1; 76 } 77 78 switch (ra->base) { 79 case CFI_UNDEFINED: 80 orc->ra_reg = ORC_REG_UNDEFINED; 81 orc->ra_offset = 0; 82 break; 83 case CFI_CFA: 84 orc->ra_reg = ORC_REG_PREV_SP; 85 orc->ra_offset = ra->offset; 86 break; 87 case CFI_FP: 88 orc->ra_reg = ORC_REG_FP; 89 break; 90 default: 91 ERROR_INSN(insn, "unknown RA base reg %d", ra->base); 92 return -1; 93 } 94 95 orc->sp_offset = cfi->cfa.offset; 96 97 return 0; 98 } 99 100 int write_orc_entry(struct elf *elf, struct section *orc_sec, 101 struct section *ip_sec, unsigned int idx, 102 struct section *insn_sec, unsigned long insn_off, 103 struct orc_entry *o) 104 { 105 struct orc_entry *orc; 106 107 /* populate ORC data */ 108 orc = (struct orc_entry *)orc_sec->data->d_buf + idx; 109 memcpy(orc, o, sizeof(*orc)); 110 111 /* populate reloc for ip */ 112 if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, 113 insn_sec, insn_off)) 114 return -1; 115 116 return 0; 117 } 118 119 static const char *reg_name(unsigned int reg) 120 { 121 switch (reg) { 122 case ORC_REG_SP: 123 return "sp"; 124 case ORC_REG_FP: 125 return "fp"; 126 case ORC_REG_PREV_SP: 127 return "prevsp"; 128 default: 129 return "?"; 130 } 131 } 132 133 static const char *orc_type_name(unsigned int type) 134 { 135 switch (type) { 136 case UNWIND_HINT_TYPE_CALL: 137 return "call"; 138 case UNWIND_HINT_TYPE_REGS: 139 return "regs"; 140 case UNWIND_HINT_TYPE_REGS_PARTIAL: 141 return "regs (partial)"; 142 default: 143 return "?"; 144 } 145 } 146 147 static void print_reg(unsigned int reg, int offset) 148 { 149 if (reg == ORC_REG_UNDEFINED) 150 printf(" (und) "); 151 else 152 printf("%s + %3d", reg_name(reg), offset); 153 154 } 155 156 void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i) 157 { 158 printf("type:%s", orc_type_name(orc[i].type)); 159 160 printf(" sp:"); 161 print_reg(orc[i].sp_reg, orc[i].sp_offset); 162 163 printf(" fp:"); 164 print_reg(orc[i].fp_reg, orc[i].fp_offset); 165 166 printf(" ra:"); 167 print_reg(orc[i].ra_reg, orc[i].ra_offset); 168 169 printf(" signal:%d\n", orc[i].signal); 170 } 171