Skip to content

Commit ab4e074

Browse files
committed
objtool: Refactor ORC section generation
Decouple ORC entries from instructions. This simplifies the control/data flow, and is going to make it easier to support alternative instructions which change the stack layout. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
1 parent 5ed934e commit ab4e074

File tree

7 files changed

+140
-159
lines changed

7 files changed

+140
-159
lines changed

tools/objtool/Makefile

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ ifeq ($(SRCARCH),x86)
4747
SUBCMD_ORC := y
4848
endif
4949

50-
ifeq ($(SUBCMD_ORC),y)
51-
CFLAGS += -DINSN_USE_ORC
52-
endif
53-
5450
export SUBCMD_CHECK SUBCMD_ORC
5551
export srctree OUTPUT CFLAGS SRCARCH AWK
5652
include $(srctree)/tools/build/Makefile.include

tools/objtool/builtin-orc.c

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,7 @@ int cmd_orc(int argc, const char **argv)
5151
if (list_empty(&file->insn_list))
5252
return 0;
5353

54-
ret = create_orc(file);
55-
if (ret)
56-
return ret;
57-
58-
ret = create_orc_sections(file);
54+
ret = orc_create(file);
5955
if (ret)
6056
return ret;
6157

tools/objtool/include/objtool/arch.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@
1111
#include <objtool/objtool.h>
1212
#include <objtool/cfi.h>
1313

14-
#ifdef INSN_USE_ORC
15-
#include <asm/orc_types.h>
16-
#endif
17-
1814
enum insn_type {
1915
INSN_JUMP_CONDITIONAL,
2016
INSN_JUMP_UNCONDITIONAL,

tools/objtool/include/objtool/check.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@ struct instruction {
4343
struct symbol *func;
4444
struct list_head stack_ops;
4545
struct cfi_state cfi;
46-
#ifdef INSN_USE_ORC
47-
struct orc_entry orc;
48-
#endif
4946
};
5047

5148
static inline bool is_static_jump(struct instruction *insn)

tools/objtool/include/objtool/objtool.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ struct objtool_file *objtool_open_read(const char *_objname);
2626

2727
int check(struct objtool_file *file);
2828
int orc_dump(const char *objname);
29-
int create_orc(struct objtool_file *file);
30-
int create_orc_sections(struct objtool_file *file);
29+
int orc_create(struct objtool_file *file);
3130

3231
#endif /* _OBJTOOL_H */

tools/objtool/orc_gen.c

Lines changed: 137 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -13,89 +13,84 @@
1313
#include <objtool/warn.h>
1414
#include <objtool/endianness.h>
1515

16-
int create_orc(struct objtool_file *file)
16+
static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi)
1717
{
18-
struct instruction *insn;
18+
struct instruction *insn = container_of(cfi, struct instruction, cfi);
19+
struct cfi_reg *bp = &cfi->regs[CFI_BP];
1920

20-
for_each_insn(file, insn) {
21-
struct orc_entry *orc = &insn->orc;
22-
struct cfi_reg *cfa = &insn->cfi.cfa;
23-
struct cfi_reg *bp = &insn->cfi.regs[CFI_BP];
21+
memset(orc, 0, sizeof(*orc));
2422

25-
if (!insn->sec->text)
26-
continue;
27-
28-
orc->end = insn->cfi.end;
23+
orc->end = cfi->end;
2924

30-
if (cfa->base == CFI_UNDEFINED) {
31-
orc->sp_reg = ORC_REG_UNDEFINED;
32-
continue;
33-
}
34-
35-
switch (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, cfa->base);
63-
return -1;
64-
}
25+
if (cfi->cfa.base == CFI_UNDEFINED) {
26+
orc->sp_reg = ORC_REG_UNDEFINED;
27+
return 0;
28+
}
6529

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;
80-
}
30+
switch (cfi->cfa.base) {
31+
case CFI_SP:
32+
orc->sp_reg = ORC_REG_SP;
33+
break;
34+
case CFI_SP_INDIRECT:
35+
orc->sp_reg = ORC_REG_SP_INDIRECT;
36+
break;
37+
case CFI_BP:
38+
orc->sp_reg = ORC_REG_BP;
39+
break;
40+
case CFI_BP_INDIRECT:
41+
orc->sp_reg = ORC_REG_BP_INDIRECT;
42+
break;
43+
case CFI_R10:
44+
orc->sp_reg = ORC_REG_R10;
45+
break;
46+
case CFI_R13:
47+
orc->sp_reg = ORC_REG_R13;
48+
break;
49+
case CFI_DI:
50+
orc->sp_reg = ORC_REG_DI;
51+
break;
52+
case CFI_DX:
53+
orc->sp_reg = ORC_REG_DX;
54+
break;
55+
default:
56+
WARN_FUNC("unknown CFA base reg %d",
57+
insn->sec, insn->offset, cfi->cfa.base);
58+
return -1;
59+
}
8160

82-
orc->sp_offset = cfa->offset;
83-
orc->bp_offset = bp->offset;
84-
orc->type = insn->cfi.type;
61+
switch (bp->base) {
62+
case CFI_UNDEFINED:
63+
orc->bp_reg = ORC_REG_UNDEFINED;
64+
break;
65+
case CFI_CFA:
66+
orc->bp_reg = ORC_REG_PREV_SP;
67+
break;
68+
case CFI_BP:
69+
orc->bp_reg = ORC_REG_BP;
70+
break;
71+
default:
72+
WARN_FUNC("unknown BP base reg %d",
73+
insn->sec, insn->offset, bp->base);
74+
return -1;
8575
}
8676

77+
orc->sp_offset = cfi->cfa.offset;
78+
orc->bp_offset = bp->offset;
79+
orc->type = cfi->type;
80+
8781
return 0;
8882
}
8983

90-
static int create_orc_entry(struct elf *elf, struct section *u_sec, struct section *ip_relocsec,
91-
unsigned int idx, struct section *insn_sec,
92-
unsigned long insn_off, struct orc_entry *o)
84+
static int write_orc_entry(struct elf *elf, struct section *orc_sec,
85+
struct section *ip_rsec, unsigned int idx,
86+
struct section *insn_sec, unsigned long insn_off,
87+
struct orc_entry *o)
9388
{
9489
struct orc_entry *orc;
9590
struct reloc *reloc;
9691

9792
/* populate ORC data */
98-
orc = (struct orc_entry *)u_sec->data->d_buf + idx;
93+
orc = (struct orc_entry *)orc_sec->data->d_buf + idx;
9994
memcpy(orc, o, sizeof(*orc));
10095
orc->sp_offset = bswap_if_needed(orc->sp_offset);
10196
orc->bp_offset = bswap_if_needed(orc->bp_offset);
@@ -117,102 +112,109 @@ static int create_orc_entry(struct elf *elf, struct section *u_sec, struct secti
117112

118113
reloc->type = R_X86_64_PC32;
119114
reloc->offset = idx * sizeof(int);
120-
reloc->sec = ip_relocsec;
115+
reloc->sec = ip_rsec;
121116

122117
elf_add_reloc(elf, reloc);
123118

124119
return 0;
125120
}
126121

127-
int create_orc_sections(struct objtool_file *file)
122+
struct orc_list_entry {
123+
struct list_head list;
124+
struct orc_entry orc;
125+
struct section *insn_sec;
126+
unsigned long insn_off;
127+
};
128+
129+
static int orc_list_add(struct list_head *orc_list, struct orc_entry *orc,
130+
struct section *sec, unsigned long offset)
131+
{
132+
struct orc_list_entry *entry = malloc(sizeof(*entry));
133+
134+
if (!entry) {
135+
WARN("malloc failed");
136+
return -1;
137+
}
138+
139+
entry->orc = *orc;
140+
entry->insn_sec = sec;
141+
entry->insn_off = offset;
142+
143+
list_add_tail(&entry->list, orc_list);
144+
return 0;
145+
}
146+
147+
int orc_create(struct objtool_file *file)
128148
{
129-
struct instruction *insn, *prev_insn;
130-
struct section *sec, *u_sec, *ip_relocsec;
131-
unsigned int idx;
149+
struct section *sec, *ip_rsec, *orc_sec;
150+
unsigned int nr = 0, idx = 0;
151+
struct orc_list_entry *entry;
152+
struct list_head orc_list;
132153

133-
struct orc_entry empty = {
134-
.sp_reg = ORC_REG_UNDEFINED,
154+
struct orc_entry null = {
155+
.sp_reg = ORC_REG_UNDEFINED,
135156
.bp_reg = ORC_REG_UNDEFINED,
136157
.type = UNWIND_HINT_TYPE_CALL,
137158
};
138159

139-
sec = find_section_by_name(file->elf, ".orc_unwind");
140-
if (sec) {
141-
WARN("file already has .orc_unwind section, skipping");
142-
return -1;
143-
}
144-
145-
/* count the number of needed orcs */
146-
idx = 0;
160+
/* Build a deduplicated list of ORC entries: */
161+
INIT_LIST_HEAD(&orc_list);
147162
for_each_sec(file, sec) {
163+
struct orc_entry orc, prev_orc = {0};
164+
struct instruction *insn;
165+
bool empty = true;
166+
148167
if (!sec->text)
149168
continue;
150169

151-
prev_insn = NULL;
152170
sec_for_each_insn(file, sec, insn) {
153-
if (!prev_insn ||
154-
memcmp(&insn->orc, &prev_insn->orc,
155-
sizeof(struct orc_entry))) {
156-
idx++;
157-
}
158-
prev_insn = insn;
171+
if (init_orc_entry(&orc, &insn->cfi))
172+
return -1;
173+
if (!memcmp(&prev_orc, &orc, sizeof(orc)))
174+
continue;
175+
if (orc_list_add(&orc_list, &orc, sec, insn->offset))
176+
return -1;
177+
nr++;
178+
prev_orc = orc;
179+
empty = false;
159180
}
160181

161-
/* section terminator */
162-
if (prev_insn)
163-
idx++;
182+
/* Add a section terminator */
183+
if (!empty) {
184+
orc_list_add(&orc_list, &null, sec, sec->len);
185+
nr++;
186+
}
164187
}
165-
if (!idx)
166-
return -1;
188+
if (!nr)
189+
return 0;
167190

191+
/* Create .orc_unwind, .orc_unwind_ip and .rela.orc_unwind_ip sections: */
192+
sec = find_section_by_name(file->elf, ".orc_unwind");
193+
if (sec) {
194+
WARN("file already has .orc_unwind section, skipping");
195+
return -1;
196+
}
197+
orc_sec = elf_create_section(file->elf, ".orc_unwind", 0,
198+
sizeof(struct orc_entry), nr);
199+
if (!orc_sec)
200+
return -1;
168201

169-
/* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
170-
sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), idx);
202+
sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), nr);
171203
if (!sec)
172204
return -1;
173-
174-
ip_relocsec = elf_create_reloc_section(file->elf, sec, SHT_RELA);
175-
if (!ip_relocsec)
205+
ip_rsec = elf_create_reloc_section(file->elf, sec, SHT_RELA);
206+
if (!ip_rsec)
176207
return -1;
177208

178-
/* create .orc_unwind section */
179-
u_sec = elf_create_section(file->elf, ".orc_unwind", 0,
180-
sizeof(struct orc_entry), idx);
181-
182-
/* populate sections */
183-
idx = 0;
184-
for_each_sec(file, sec) {
185-
if (!sec->text)
186-
continue;
187-
188-
prev_insn = NULL;
189-
sec_for_each_insn(file, sec, insn) {
190-
if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc,
191-
sizeof(struct orc_entry))) {
192-
193-
if (create_orc_entry(file->elf, u_sec, ip_relocsec, idx,
194-
insn->sec, insn->offset,
195-
&insn->orc))
196-
return -1;
197-
198-
idx++;
199-
}
200-
prev_insn = insn;
201-
}
202-
203-
/* section terminator */
204-
if (prev_insn) {
205-
if (create_orc_entry(file->elf, u_sec, ip_relocsec, idx,
206-
prev_insn->sec,
207-
prev_insn->offset + prev_insn->len,
208-
&empty))
209-
return -1;
210-
211-
idx++;
212-
}
209+
/* Write ORC entries to sections: */
210+
list_for_each_entry(entry, &orc_list, list) {
211+
if (write_orc_entry(file->elf, orc_sec, ip_rsec, idx++,
212+
entry->insn_sec, entry->insn_off,
213+
&entry->orc))
214+
return -1;
213215
}
214216

215-
if (elf_rebuild_reloc_section(file->elf, ip_relocsec))
217+
if (elf_rebuild_reloc_section(file->elf, ip_rsec))
216218
return -1;
217219

218220
return 0;

tools/objtool/weak.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,7 @@ int __weak orc_dump(const char *_objname)
2525
UNSUPPORTED("orc");
2626
}
2727

28-
int __weak create_orc(struct objtool_file *file)
29-
{
30-
UNSUPPORTED("orc");
31-
}
32-
33-
int __weak create_orc_sections(struct objtool_file *file)
28+
int __weak orc_create(struct objtool_file *file)
3429
{
3530
UNSUPPORTED("orc");
3631
}

0 commit comments

Comments
 (0)