1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <objtool/check.h> 6 #include <objtool/disas.h> 7 #include <objtool/elf.h> 8 #include <objtool/arch.h> 9 #include <objtool/warn.h> 10 #include <objtool/builtin.h> 11 12 const char *arch_reg_name[CFI_NUM_REGS] = { 13 "r0", "sp", "r2", "r3", 14 "r4", "r5", "r6", "r7", 15 "r8", "r9", "r10", "r11", 16 "r12", "r13", "r14", "r15", 17 "r16", "r17", "r18", "r19", 18 "r20", "r21", "r22", "r23", 19 "r24", "r25", "r26", "r27", 20 "r28", "r29", "r30", "r31", 21 "ra" 22 }; 23 24 int arch_ftrace_match(const char *name) 25 { 26 return !strcmp(name, "_mcount"); 27 } 28 29 s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *reloc) 30 { 31 return reloc_addend(reloc); 32 } 33 34 bool arch_callee_saved_reg(unsigned char reg) 35 { 36 return false; 37 } 38 39 int arch_decode_hint_reg(u8 sp_reg, int *base) 40 { 41 exit(-1); 42 } 43 44 const char *arch_nop_insn(int len) 45 { 46 exit(-1); 47 } 48 49 const char *arch_ret_insn(int len) 50 { 51 exit(-1); 52 } 53 54 int arch_decode_instruction(struct objtool_file *file, const struct section *sec, 55 unsigned long offset, unsigned int maxlen, 56 struct instruction *insn) 57 { 58 unsigned int opcode; 59 enum insn_type typ; 60 unsigned long imm; 61 u32 ins; 62 63 ins = bswap_if_needed(file->elf, *(u32 *)(sec->data->d_buf + offset)); 64 opcode = ins >> 26; 65 typ = INSN_OTHER; 66 imm = 0; 67 68 switch (opcode) { 69 case 18: /* b[l][a] */ 70 if (ins == 0x48000005) /* bl .+4 */ 71 typ = INSN_OTHER; 72 else if (ins & 1) /* bl[a] */ 73 typ = INSN_CALL; 74 else /* b[a] */ 75 typ = INSN_JUMP_UNCONDITIONAL; 76 77 imm = ins & 0x3fffffc; 78 if (imm & 0x2000000) 79 imm -= 0x4000000; 80 imm |= ins & 2; /* AA flag */ 81 break; 82 } 83 84 if (opcode == 1) 85 insn->len = 8; 86 else 87 insn->len = 4; 88 89 insn->type = typ; 90 insn->immediate = imm; 91 92 return 0; 93 } 94 95 unsigned long arch_jump_destination(struct instruction *insn) 96 { 97 if (insn->immediate & 2) 98 return insn->immediate & ~2; 99 100 return insn->offset + insn->immediate; 101 } 102 103 bool arch_pc_relative_reloc(struct reloc *reloc) 104 { 105 /* 106 * The powerpc build only allows certain relocation types, see 107 * relocs_check.sh, and none of those accepted are PC relative. 108 */ 109 return false; 110 } 111 112 void arch_initial_func_cfi_state(struct cfi_init_state *state) 113 { 114 int i; 115 116 for (i = 0; i < CFI_NUM_REGS; i++) { 117 state->regs[i].base = CFI_UNDEFINED; 118 state->regs[i].offset = 0; 119 } 120 121 /* initial CFA (call frame address) */ 122 state->cfa.base = CFI_SP; 123 state->cfa.offset = 0; 124 125 /* initial LR (return address) */ 126 state->regs[CFI_RA].base = CFI_CFA; 127 state->regs[CFI_RA].offset = 0; 128 } 129 130 unsigned int arch_reloc_size(struct reloc *reloc) 131 { 132 switch (reloc_type(reloc)) { 133 case R_PPC_REL32: 134 case R_PPC_ADDR32: 135 case R_PPC_UADDR32: 136 case R_PPC_PLT32: 137 case R_PPC_PLTREL32: 138 return 4; 139 default: 140 return 8; 141 } 142 } 143 144 #ifdef DISAS 145 146 int arch_disas_info_init(struct disassemble_info *dinfo) 147 { 148 return disas_info_init(dinfo, bfd_arch_powerpc, 149 bfd_mach_ppc, bfd_mach_ppc64, 150 NULL); 151 } 152 153 #endif /* DISAS */ 154