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 *bp = &cfi->regs[CFI_BP]; 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 WARN_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_SP_INDIRECT: 54 orc->sp_reg = ORC_REG_SP_INDIRECT; 55 break; 56 case CFI_BP: 57 orc->sp_reg = ORC_REG_BP; 58 break; 59 case CFI_BP_INDIRECT: 60 orc->sp_reg = ORC_REG_BP_INDIRECT; 61 break; 62 case CFI_R10: 63 orc->sp_reg = ORC_REG_R10; 64 break; 65 case CFI_R13: 66 orc->sp_reg = ORC_REG_R13; 67 break; 68 case CFI_DI: 69 orc->sp_reg = ORC_REG_DI; 70 break; 71 case CFI_DX: 72 orc->sp_reg = ORC_REG_DX; 73 break; 74 default: 75 WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); 76 return -1; 77 } 78 79 switch (bp->base) { 80 case CFI_UNDEFINED: 81 orc->bp_reg = ORC_REG_UNDEFINED; 82 break; 83 case CFI_CFA: 84 orc->bp_reg = ORC_REG_PREV_SP; 85 break; 86 case CFI_BP: 87 orc->bp_reg = ORC_REG_BP; 88 break; 89 default: 90 WARN_INSN(insn, "unknown BP base reg %d", bp->base); 91 return -1; 92 } 93 94 orc->sp_offset = cfi->cfa.offset; 95 orc->bp_offset = bp->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 orc->sp_offset = bswap_if_needed(elf, orc->sp_offset); 111 orc->bp_offset = bswap_if_needed(elf, orc->bp_offset); 112 113 /* populate reloc for ip */ 114 if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, 115 insn_sec, insn_off)) 116 return -1; 117 118 return 0; 119 } 120 121 static const char *reg_name(unsigned int reg) 122 { 123 switch (reg) { 124 case ORC_REG_PREV_SP: 125 return "prevsp"; 126 case ORC_REG_DX: 127 return "dx"; 128 case ORC_REG_DI: 129 return "di"; 130 case ORC_REG_BP: 131 return "bp"; 132 case ORC_REG_SP: 133 return "sp"; 134 case ORC_REG_R10: 135 return "r10"; 136 case ORC_REG_R13: 137 return "r13"; 138 case ORC_REG_BP_INDIRECT: 139 return "bp(ind)"; 140 case ORC_REG_SP_INDIRECT: 141 return "sp(ind)"; 142 default: 143 return "?"; 144 } 145 } 146 147 static const char *orc_type_name(unsigned int type) 148 { 149 switch (type) { 150 case ORC_TYPE_UNDEFINED: 151 return "(und)"; 152 case ORC_TYPE_END_OF_STACK: 153 return "end"; 154 case ORC_TYPE_CALL: 155 return "call"; 156 case ORC_TYPE_REGS: 157 return "regs"; 158 case ORC_TYPE_REGS_PARTIAL: 159 return "regs (partial)"; 160 default: 161 return "?"; 162 } 163 } 164 165 static void print_reg(unsigned int reg, int offset) 166 { 167 if (reg == ORC_REG_BP_INDIRECT) 168 printf("(bp%+d)", offset); 169 else if (reg == ORC_REG_SP_INDIRECT) 170 printf("(sp)%+d", offset); 171 else if (reg == ORC_REG_UNDEFINED) 172 printf("(und)"); 173 else 174 printf("%s%+d", reg_name(reg), offset); 175 } 176 177 void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i) 178 { 179 printf("type:%s", orc_type_name(orc[i].type)); 180 181 printf(" sp:"); 182 print_reg(orc[i].sp_reg, bswap_if_needed(dummy_elf, orc[i].sp_offset)); 183 184 printf(" bp:"); 185 print_reg(orc[i].bp_reg, bswap_if_needed(dummy_elf, orc[i].bp_offset)); 186 187 printf(" signal:%d\n", orc[i].signal); 188 } 189
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.