xref: /linux/tools/objtool/arch/powerpc/decode.c (revision 7482c19173b7eb044d476b3444d7ee55bc669d03)
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/elf.h>
7 #include <objtool/arch.h>
8 #include <objtool/warn.h>
9 #include <objtool/builtin.h>
10 #include <objtool/endianness.h>
11 
12 int arch_ftrace_match(char *name)
13 {
14 	return !strcmp(name, "_mcount");
15 }
16 
17 unsigned long arch_dest_reloc_offset(int addend)
18 {
19 	return addend;
20 }
21 
22 bool arch_callee_saved_reg(unsigned char reg)
23 {
24 	return false;
25 }
26 
27 int arch_decode_hint_reg(u8 sp_reg, int *base)
28 {
29 	exit(-1);
30 }
31 
32 const char *arch_nop_insn(int len)
33 {
34 	exit(-1);
35 }
36 
37 const char *arch_ret_insn(int len)
38 {
39 	exit(-1);
40 }
41 
42 int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
43 			    unsigned long offset, unsigned int maxlen,
44 			    unsigned int *len, enum insn_type *type,
45 			    unsigned long *immediate,
46 			    struct list_head *ops_list)
47 {
48 	unsigned int opcode;
49 	enum insn_type typ;
50 	unsigned long imm;
51 	u32 insn;
52 
53 	insn = bswap_if_needed(file->elf, *(u32 *)(sec->data->d_buf + offset));
54 	opcode = insn >> 26;
55 	typ = INSN_OTHER;
56 	imm = 0;
57 
58 	switch (opcode) {
59 	case 18: /* b[l][a] */
60 		if ((insn & 3) == 1) /* bl */
61 			typ = INSN_CALL;
62 
63 		imm = insn & 0x3fffffc;
64 		if (imm & 0x2000000)
65 			imm -= 0x4000000;
66 		break;
67 	}
68 
69 	if (opcode == 1)
70 		*len = 8;
71 	else
72 		*len = 4;
73 
74 	*type = typ;
75 	*immediate = imm;
76 
77 	return 0;
78 }
79 
80 unsigned long arch_jump_destination(struct instruction *insn)
81 {
82 	return insn->offset + insn->immediate;
83 }
84 
85 bool arch_pc_relative_reloc(struct reloc *reloc)
86 {
87 	/*
88 	 * The powerpc build only allows certain relocation types, see
89 	 * relocs_check.sh, and none of those accepted are PC relative.
90 	 */
91 	return false;
92 }
93 
94 void arch_initial_func_cfi_state(struct cfi_init_state *state)
95 {
96 	int i;
97 
98 	for (i = 0; i < CFI_NUM_REGS; i++) {
99 		state->regs[i].base = CFI_UNDEFINED;
100 		state->regs[i].offset = 0;
101 	}
102 
103 	/* initial CFA (call frame address) */
104 	state->cfa.base = CFI_SP;
105 	state->cfa.offset = 0;
106 
107 	/* initial LR (return address) */
108 	state->regs[CFI_RA].base = CFI_CFA;
109 	state->regs[CFI_RA].offset = 0;
110 }
111