hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/tools/objtool/orc_gen.c
....@@ -1,242 +1,242 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
3
- *
4
- * This program is free software; you can redistribute it and/or
5
- * modify it under the terms of the GNU General Public License
6
- * as published by the Free Software Foundation; either version 2
7
- * of the License, or (at your option) any later version.
8
- *
9
- * This program is distributed in the hope that it will be useful,
10
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- * GNU General Public License for more details.
13
- *
14
- * You should have received a copy of the GNU General Public License
15
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
164 */
175
186 #include <stdlib.h>
197 #include <string.h>
208
21
-#include "orc.h"
9
+#include <linux/objtool.h>
10
+#include <asm/orc_types.h>
11
+
2212 #include "check.h"
2313 #include "warn.h"
2414
25
-int create_orc(struct objtool_file *file)
15
+static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi,
16
+ struct instruction *insn)
2617 {
27
- struct instruction *insn;
18
+ struct cfi_reg *bp = &cfi->regs[CFI_BP];
2819
29
- for_each_insn(file, insn) {
30
- struct orc_entry *orc = &insn->orc;
31
- struct cfi_reg *cfa = &insn->state.cfa;
32
- struct cfi_reg *bp = &insn->state.regs[CFI_BP];
20
+ memset(orc, 0, sizeof(*orc));
3321
34
- orc->end = insn->state.end;
35
-
36
- if (cfa->base == CFI_UNDEFINED) {
37
- orc->sp_reg = ORC_REG_UNDEFINED;
38
- continue;
39
- }
40
-
41
- switch (cfa->base) {
42
- case CFI_SP:
43
- orc->sp_reg = ORC_REG_SP;
44
- break;
45
- case CFI_SP_INDIRECT:
46
- orc->sp_reg = ORC_REG_SP_INDIRECT;
47
- break;
48
- case CFI_BP:
49
- orc->sp_reg = ORC_REG_BP;
50
- break;
51
- case CFI_BP_INDIRECT:
52
- orc->sp_reg = ORC_REG_BP_INDIRECT;
53
- break;
54
- case CFI_R10:
55
- orc->sp_reg = ORC_REG_R10;
56
- break;
57
- case CFI_R13:
58
- orc->sp_reg = ORC_REG_R13;
59
- break;
60
- case CFI_DI:
61
- orc->sp_reg = ORC_REG_DI;
62
- break;
63
- case CFI_DX:
64
- orc->sp_reg = ORC_REG_DX;
65
- break;
66
- default:
67
- WARN_FUNC("unknown CFA base reg %d",
68
- insn->sec, insn->offset, cfa->base);
69
- return -1;
70
- }
71
-
72
- switch(bp->base) {
73
- case CFI_UNDEFINED:
74
- orc->bp_reg = ORC_REG_UNDEFINED;
75
- break;
76
- case CFI_CFA:
77
- orc->bp_reg = ORC_REG_PREV_SP;
78
- break;
79
- case CFI_BP:
80
- orc->bp_reg = ORC_REG_BP;
81
- break;
82
- default:
83
- WARN_FUNC("unknown BP base reg %d",
84
- insn->sec, insn->offset, bp->base);
85
- return -1;
86
- }
87
-
88
- orc->sp_offset = cfa->offset;
89
- orc->bp_offset = bp->offset;
90
- orc->type = insn->state.type;
22
+ if (!cfi) {
23
+ orc->end = 0;
24
+ orc->sp_reg = ORC_REG_UNDEFINED;
25
+ return 0;
9126 }
9227
93
- return 0;
94
-}
28
+ orc->end = cfi->end;
9529
96
-static int create_orc_entry(struct section *u_sec, struct section *ip_relasec,
97
- unsigned int idx, struct section *insn_sec,
98
- unsigned long insn_off, struct orc_entry *o)
99
-{
100
- struct orc_entry *orc;
101
- struct rela *rela;
30
+ if (cfi->cfa.base == CFI_UNDEFINED) {
31
+ orc->sp_reg = ORC_REG_UNDEFINED;
32
+ return 0;
33
+ }
10234
103
- /* populate ORC data */
104
- orc = (struct orc_entry *)u_sec->data->d_buf + idx;
105
- memcpy(orc, o, sizeof(*orc));
106
-
107
- /* populate rela for ip */
108
- rela = malloc(sizeof(*rela));
109
- if (!rela) {
110
- perror("malloc");
35
+ switch (cfi->cfa.base) {
36
+ case CFI_SP:
37
+ orc->sp_reg = ORC_REG_SP;
38
+ break;
39
+ case CFI_SP_INDIRECT:
40
+ orc->sp_reg = ORC_REG_SP_INDIRECT;
41
+ break;
42
+ case CFI_BP:
43
+ orc->sp_reg = ORC_REG_BP;
44
+ break;
45
+ case CFI_BP_INDIRECT:
46
+ orc->sp_reg = ORC_REG_BP_INDIRECT;
47
+ break;
48
+ case CFI_R10:
49
+ orc->sp_reg = ORC_REG_R10;
50
+ break;
51
+ case CFI_R13:
52
+ orc->sp_reg = ORC_REG_R13;
53
+ break;
54
+ case CFI_DI:
55
+ orc->sp_reg = ORC_REG_DI;
56
+ break;
57
+ case CFI_DX:
58
+ orc->sp_reg = ORC_REG_DX;
59
+ break;
60
+ default:
61
+ WARN_FUNC("unknown CFA base reg %d",
62
+ insn->sec, insn->offset, cfi->cfa.base);
11163 return -1;
11264 }
113
- memset(rela, 0, sizeof(*rela));
11465
115
- if (insn_sec->sym) {
116
- rela->sym = insn_sec->sym;
117
- rela->addend = insn_off;
118
- } else {
119
- /*
120
- * The Clang assembler doesn't produce section symbols, so we
121
- * have to reference the function symbol instead:
122
- */
123
- rela->sym = find_symbol_containing(insn_sec, insn_off);
124
- if (!rela->sym) {
125
- /*
126
- * Hack alert. This happens when we need to reference
127
- * the NOP pad insn immediately after the function.
128
- */
129
- rela->sym = find_symbol_containing(insn_sec,
130
- insn_off - 1);
131
- }
132
- if (!rela->sym) {
133
- WARN("missing symbol for insn at offset 0x%lx\n",
134
- insn_off);
135
- return -1;
136
- }
137
-
138
- rela->addend = insn_off - rela->sym->offset;
66
+ switch (bp->base) {
67
+ case CFI_UNDEFINED:
68
+ orc->bp_reg = ORC_REG_UNDEFINED;
69
+ break;
70
+ case CFI_CFA:
71
+ orc->bp_reg = ORC_REG_PREV_SP;
72
+ break;
73
+ case CFI_BP:
74
+ orc->bp_reg = ORC_REG_BP;
75
+ break;
76
+ default:
77
+ WARN_FUNC("unknown BP base reg %d",
78
+ insn->sec, insn->offset, bp->base);
79
+ return -1;
13980 }
14081
141
- rela->type = R_X86_64_PC32;
142
- rela->offset = idx * sizeof(int);
143
-
144
- list_add_tail(&rela->list, &ip_relasec->rela_list);
145
- hash_add(ip_relasec->rela_hash, &rela->hash, rela->offset);
82
+ orc->sp_offset = cfi->cfa.offset;
83
+ orc->bp_offset = bp->offset;
84
+ orc->type = cfi->type;
14685
14786 return 0;
14887 }
14988
150
-int create_orc_sections(struct objtool_file *file)
89
+static int write_orc_entry(struct elf *elf, struct section *orc_sec,
90
+ struct section *ip_sec, unsigned int idx,
91
+ struct section *insn_sec, unsigned long insn_off,
92
+ struct orc_entry *o)
15193 {
152
- struct instruction *insn, *prev_insn;
153
- struct section *sec, *u_sec, *ip_relasec;
154
- unsigned int idx;
94
+ struct orc_entry *orc;
15595
156
- struct orc_entry empty = {
157
- .sp_reg = ORC_REG_UNDEFINED,
96
+ /* populate ORC data */
97
+ orc = (struct orc_entry *)orc_sec->data->d_buf + idx;
98
+ memcpy(orc, o, sizeof(*orc));
99
+
100
+ /* populate reloc for ip */
101
+ if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32,
102
+ insn_sec, insn_off))
103
+ return -1;
104
+
105
+ return 0;
106
+}
107
+
108
+struct orc_list_entry {
109
+ struct list_head list;
110
+ struct orc_entry orc;
111
+ struct section *insn_sec;
112
+ unsigned long insn_off;
113
+};
114
+
115
+static int orc_list_add(struct list_head *orc_list, struct orc_entry *orc,
116
+ struct section *sec, unsigned long offset)
117
+{
118
+ struct orc_list_entry *entry = malloc(sizeof(*entry));
119
+
120
+ if (!entry) {
121
+ WARN("malloc failed");
122
+ return -1;
123
+ }
124
+
125
+ entry->orc = *orc;
126
+ entry->insn_sec = sec;
127
+ entry->insn_off = offset;
128
+
129
+ list_add_tail(&entry->list, orc_list);
130
+ return 0;
131
+}
132
+
133
+static unsigned long alt_group_len(struct alt_group *alt_group)
134
+{
135
+ return alt_group->last_insn->offset +
136
+ alt_group->last_insn->len -
137
+ alt_group->first_insn->offset;
138
+}
139
+
140
+int orc_create(struct objtool_file *file)
141
+{
142
+ struct section *sec, *orc_sec;
143
+ unsigned int nr = 0, idx = 0;
144
+ struct orc_list_entry *entry;
145
+ struct list_head orc_list;
146
+
147
+ struct orc_entry null = {
148
+ .sp_reg = ORC_REG_UNDEFINED,
158149 .bp_reg = ORC_REG_UNDEFINED,
159
- .type = ORC_TYPE_CALL,
150
+ .type = UNWIND_HINT_TYPE_CALL,
160151 };
161152
153
+ /* Build a deduplicated list of ORC entries: */
154
+ INIT_LIST_HEAD(&orc_list);
155
+ for_each_sec(file, sec) {
156
+ struct orc_entry orc, prev_orc = {0};
157
+ struct instruction *insn;
158
+ bool empty = true;
159
+
160
+ if (!sec->text)
161
+ continue;
162
+
163
+ sec_for_each_insn(file, sec, insn) {
164
+ struct alt_group *alt_group = insn->alt_group;
165
+ int i;
166
+
167
+ if (!alt_group) {
168
+ if (init_orc_entry(&orc, insn->cfi, insn))
169
+ return -1;
170
+ if (!memcmp(&prev_orc, &orc, sizeof(orc)))
171
+ continue;
172
+ if (orc_list_add(&orc_list, &orc, sec,
173
+ insn->offset))
174
+ return -1;
175
+ nr++;
176
+ prev_orc = orc;
177
+ empty = false;
178
+ continue;
179
+ }
180
+
181
+ /*
182
+ * Alternatives can have different stack layout
183
+ * possibilities (but they shouldn't conflict).
184
+ * Instead of traversing the instructions, use the
185
+ * alt_group's flattened byte-offset-addressed CFI
186
+ * array.
187
+ */
188
+ for (i = 0; i < alt_group_len(alt_group); i++) {
189
+ struct cfi_state *cfi = alt_group->cfi[i];
190
+ if (!cfi)
191
+ continue;
192
+ /* errors are reported on the original insn */
193
+ if (init_orc_entry(&orc, cfi, insn))
194
+ return -1;
195
+ if (!memcmp(&prev_orc, &orc, sizeof(orc)))
196
+ continue;
197
+ if (orc_list_add(&orc_list, &orc, insn->sec,
198
+ insn->offset + i))
199
+ return -1;
200
+ nr++;
201
+ prev_orc = orc;
202
+ empty = false;
203
+ }
204
+
205
+ /* Skip to the end of the alt_group */
206
+ insn = alt_group->last_insn;
207
+ }
208
+
209
+ /* Add a section terminator */
210
+ if (!empty) {
211
+ orc_list_add(&orc_list, &null, sec, sec->len);
212
+ nr++;
213
+ }
214
+ }
215
+ if (!nr)
216
+ return 0;
217
+
218
+ /* Create .orc_unwind, .orc_unwind_ip and .rela.orc_unwind_ip sections: */
162219 sec = find_section_by_name(file->elf, ".orc_unwind");
163220 if (sec) {
164221 WARN("file already has .orc_unwind section, skipping");
165222 return -1;
166223 }
167
-
168
- /* count the number of needed orcs */
169
- idx = 0;
170
- for_each_sec(file, sec) {
171
- if (!sec->text)
172
- continue;
173
-
174
- prev_insn = NULL;
175
- sec_for_each_insn(file, sec, insn) {
176
- if (!prev_insn ||
177
- memcmp(&insn->orc, &prev_insn->orc,
178
- sizeof(struct orc_entry))) {
179
- idx++;
180
- }
181
- prev_insn = insn;
182
- }
183
-
184
- /* section terminator */
185
- if (prev_insn)
186
- idx++;
187
- }
188
- if (!idx)
224
+ orc_sec = elf_create_section(file->elf, ".orc_unwind", 0,
225
+ sizeof(struct orc_entry), nr);
226
+ if (!orc_sec)
189227 return -1;
190228
191
-
192
- /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
193
- sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx);
229
+ sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), nr);
194230 if (!sec)
195231 return -1;
196232
197
- ip_relasec = elf_create_rela_section(file->elf, sec);
198
- if (!ip_relasec)
199
- return -1;
200
-
201
- /* create .orc_unwind section */
202
- u_sec = elf_create_section(file->elf, ".orc_unwind",
203
- sizeof(struct orc_entry), idx);
204
-
205
- /* populate sections */
206
- idx = 0;
207
- for_each_sec(file, sec) {
208
- if (!sec->text)
209
- continue;
210
-
211
- prev_insn = NULL;
212
- sec_for_each_insn(file, sec, insn) {
213
- if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc,
214
- sizeof(struct orc_entry))) {
215
-
216
- if (create_orc_entry(u_sec, ip_relasec, idx,
217
- insn->sec, insn->offset,
218
- &insn->orc))
219
- return -1;
220
-
221
- idx++;
222
- }
223
- prev_insn = insn;
224
- }
225
-
226
- /* section terminator */
227
- if (prev_insn) {
228
- if (create_orc_entry(u_sec, ip_relasec, idx,
229
- prev_insn->sec,
230
- prev_insn->offset + prev_insn->len,
231
- &empty))
232
- return -1;
233
-
234
- idx++;
235
- }
233
+ /* Write ORC entries to sections: */
234
+ list_for_each_entry(entry, &orc_list, list) {
235
+ if (write_orc_entry(file->elf, orc_sec, sec, idx++,
236
+ entry->insn_sec, entry->insn_off,
237
+ &entry->orc))
238
+ return -1;
236239 }
237
-
238
- if (elf_rebuild_rela_section(ip_relasec))
239
- return -1;
240240
241241 return 0;
242242 }