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
9int 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(s: orc, c: 0, n: 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
99int 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(dest: orc, src: o, n: 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, sec: ip_sec, offset: idx * sizeof(int), reloc_idx: idx,
114 insn_sec, insn_off))
115 return -1;
116
117 return 0;
118}
119
120static 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
146static 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
164static void print_reg(unsigned int reg, int offset)
165{
166 if (reg == ORC_REG_BP_INDIRECT)
167 printf(format: "(bp%+d)", offset);
168 else if (reg == ORC_REG_SP_INDIRECT)
169 printf(format: "(sp)%+d", offset);
170 else if (reg == ORC_REG_UNDEFINED)
171 printf(format: "(und)");
172 else
173 printf(format: "%s%+d", reg_name(reg), offset);
174}
175
176void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i)
177{
178 printf(format: "type:%s", orc_type_name(type: orc[i].type));
179
180 printf(format: " sp:");
181 print_reg(reg: orc[i].sp_reg, bswap_if_needed(dummy_elf, orc[i].sp_offset));
182
183 printf(format: " bp:");
184 print_reg(reg: orc[i].bp_reg, bswap_if_needed(dummy_elf, orc[i].bp_offset));
185
186 printf(format: " signal:%d\n", orc[i].signal);
187}
188

source code of linux/tools/objtool/arch/x86/orc.c