xref: /linux/tools/objtool/arch/x86/orc.c (revision 7fc2cd2e4b398c57c9cf961cfea05eadbf34c05c)
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 *bp = &cfi->regs[CFI_BP];
12 
13 	memset(orc, 0, sizeof(*orc));
14 
15 	if (!cfi) {
16 		/*
17 		 * This is usually either unreachable nops/traps (which don't
18 		 * trigger unreachable instruction warnings), or
19 		 * STACK_FRAME_NON_STANDARD functions.
20 		 */
21 		orc->type = ORC_TYPE_UNDEFINED;
22 		return 0;
23 	}
24 
25 	switch (cfi->type) {
26 	case UNWIND_HINT_TYPE_UNDEFINED:
27 		orc->type = ORC_TYPE_UNDEFINED;
28 		return 0;
29 	case UNWIND_HINT_TYPE_END_OF_STACK:
30 		orc->type = ORC_TYPE_END_OF_STACK;
31 		return 0;
32 	case UNWIND_HINT_TYPE_CALL:
33 		orc->type = ORC_TYPE_CALL;
34 		break;
35 	case UNWIND_HINT_TYPE_REGS:
36 		orc->type = ORC_TYPE_REGS;
37 		break;
38 	case UNWIND_HINT_TYPE_REGS_PARTIAL:
39 		orc->type = ORC_TYPE_REGS_PARTIAL;
40 		break;
41 	default:
42 		ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type);
43 		return -1;
44 	}
45 
46 	orc->signal = cfi->signal;
47 
48 	switch (cfi->cfa.base) {
49 	case CFI_SP:
50 		orc->sp_reg = ORC_REG_SP;
51 		break;
52 	case CFI_SP_INDIRECT:
53 		orc->sp_reg = ORC_REG_SP_INDIRECT;
54 		break;
55 	case CFI_BP:
56 		orc->sp_reg = ORC_REG_BP;
57 		break;
58 	case CFI_BP_INDIRECT:
59 		orc->sp_reg = ORC_REG_BP_INDIRECT;
60 		break;
61 	case CFI_R10:
62 		orc->sp_reg = ORC_REG_R10;
63 		break;
64 	case CFI_R13:
65 		orc->sp_reg = ORC_REG_R13;
66 		break;
67 	case CFI_DI:
68 		orc->sp_reg = ORC_REG_DI;
69 		break;
70 	case CFI_DX:
71 		orc->sp_reg = ORC_REG_DX;
72 		break;
73 	default:
74 		ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
75 		return -1;
76 	}
77 
78 	switch (bp->base) {
79 	case CFI_UNDEFINED:
80 		orc->bp_reg = ORC_REG_UNDEFINED;
81 		break;
82 	case CFI_CFA:
83 		orc->bp_reg = ORC_REG_PREV_SP;
84 		break;
85 	case CFI_BP:
86 		orc->bp_reg = ORC_REG_BP;
87 		break;
88 	default:
89 		ERROR_INSN(insn, "unknown BP base reg %d", bp->base);
90 		return -1;
91 	}
92 
93 	orc->sp_offset = cfi->cfa.offset;
94 	orc->bp_offset = bp->offset;
95 
96 	return 0;
97 }
98 
99 int write_orc_entry(struct elf *elf, struct section *orc_sec,
100 		    struct section *ip_sec, unsigned int idx,
101 		    struct section *insn_sec, unsigned long insn_off,
102 		    struct orc_entry *o)
103 {
104 	struct orc_entry *orc;
105 
106 	/* populate ORC data */
107 	orc = (struct orc_entry *)orc_sec->data->d_buf + idx;
108 	memcpy(orc, o, sizeof(*orc));
109 	orc->sp_offset = bswap_if_needed(elf, orc->sp_offset);
110 	orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);
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_PREV_SP:
124 		return "prevsp";
125 	case ORC_REG_DX:
126 		return "dx";
127 	case ORC_REG_DI:
128 		return "di";
129 	case ORC_REG_BP:
130 		return "bp";
131 	case ORC_REG_SP:
132 		return "sp";
133 	case ORC_REG_R10:
134 		return "r10";
135 	case ORC_REG_R13:
136 		return "r13";
137 	case ORC_REG_BP_INDIRECT:
138 		return "bp(ind)";
139 	case ORC_REG_SP_INDIRECT:
140 		return "sp(ind)";
141 	default:
142 		return "?";
143 	}
144 }
145 
146 static const char *orc_type_name(unsigned int type)
147 {
148 	switch (type) {
149 	case ORC_TYPE_UNDEFINED:
150 		return "(und)";
151 	case ORC_TYPE_END_OF_STACK:
152 		return "end";
153 	case ORC_TYPE_CALL:
154 		return "call";
155 	case ORC_TYPE_REGS:
156 		return "regs";
157 	case ORC_TYPE_REGS_PARTIAL:
158 		return "regs (partial)";
159 	default:
160 		return "?";
161 	}
162 }
163 
164 static void print_reg(unsigned int reg, int offset)
165 {
166 	if (reg == ORC_REG_BP_INDIRECT)
167 		printf("(bp%+d)", offset);
168 	else if (reg == ORC_REG_SP_INDIRECT)
169 		printf("(sp)%+d", offset);
170 	else if (reg == ORC_REG_UNDEFINED)
171 		printf("(und)");
172 	else
173 		printf("%s%+d", reg_name(reg), offset);
174 }
175 
176 void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i)
177 {
178 	printf("type:%s", orc_type_name(orc[i].type));
179 
180 	printf(" sp:");
181 	print_reg(orc[i].sp_reg, bswap_if_needed(dummy_elf, orc[i].sp_offset));
182 
183 	printf(" bp:");
184 	print_reg(orc[i].bp_reg, bswap_if_needed(dummy_elf, orc[i].bp_offset));
185 
186 	printf(" signal:%d\n", orc[i].signal);
187 }
188