1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
13 int create_orc(struct objtool_file
*file
)
15 struct instruction
*insn
;
17 for_each_insn(file
, insn
) {
18 struct orc_entry
*orc
= &insn
->orc
;
19 struct cfi_reg
*cfa
= &insn
->state
.cfa
;
20 struct cfi_reg
*bp
= &insn
->state
.regs
[CFI_BP
];
22 orc
->end
= insn
->state
.end
;
24 if (cfa
->base
== CFI_UNDEFINED
) {
25 orc
->sp_reg
= ORC_REG_UNDEFINED
;
31 orc
->sp_reg
= ORC_REG_SP
;
34 orc
->sp_reg
= ORC_REG_SP_INDIRECT
;
37 orc
->sp_reg
= ORC_REG_BP
;
40 orc
->sp_reg
= ORC_REG_BP_INDIRECT
;
43 orc
->sp_reg
= ORC_REG_R10
;
46 orc
->sp_reg
= ORC_REG_R13
;
49 orc
->sp_reg
= ORC_REG_DI
;
52 orc
->sp_reg
= ORC_REG_DX
;
55 WARN_FUNC("unknown CFA base reg %d",
56 insn
->sec
, insn
->offset
, cfa
->base
);
62 orc
->bp_reg
= ORC_REG_UNDEFINED
;
65 orc
->bp_reg
= ORC_REG_PREV_SP
;
68 orc
->bp_reg
= ORC_REG_BP
;
71 WARN_FUNC("unknown BP base reg %d",
72 insn
->sec
, insn
->offset
, bp
->base
);
76 orc
->sp_offset
= cfa
->offset
;
77 orc
->bp_offset
= bp
->offset
;
78 orc
->type
= insn
->state
.type
;
84 static int create_orc_entry(struct elf
*elf
, struct section
*u_sec
, struct section
*ip_relasec
,
85 unsigned int idx
, struct section
*insn_sec
,
86 unsigned long insn_off
, struct orc_entry
*o
)
88 struct orc_entry
*orc
;
91 /* populate ORC data */
92 orc
= (struct orc_entry
*)u_sec
->data
->d_buf
+ idx
;
93 memcpy(orc
, o
, sizeof(*orc
));
95 /* populate rela for ip */
96 rela
= malloc(sizeof(*rela
));
101 memset(rela
, 0, sizeof(*rela
));
104 rela
->sym
= insn_sec
->sym
;
105 rela
->addend
= insn_off
;
108 * The Clang assembler doesn't produce section symbols, so we
109 * have to reference the function symbol instead:
111 rela
->sym
= find_symbol_containing(insn_sec
, insn_off
);
114 * Hack alert. This happens when we need to reference
115 * the NOP pad insn immediately after the function.
117 rela
->sym
= find_symbol_containing(insn_sec
,
121 WARN("missing symbol for insn at offset 0x%lx\n",
126 rela
->addend
= insn_off
- rela
->sym
->offset
;
129 rela
->type
= R_X86_64_PC32
;
130 rela
->offset
= idx
* sizeof(int);
131 rela
->sec
= ip_relasec
;
133 list_add_tail(&rela
->list
, &ip_relasec
->rela_list
);
134 hash_add(elf
->rela_hash
, &rela
->hash
, rela_hash(rela
));
139 int create_orc_sections(struct objtool_file
*file
)
141 struct instruction
*insn
, *prev_insn
;
142 struct section
*sec
, *u_sec
, *ip_relasec
;
145 struct orc_entry empty
= {
146 .sp_reg
= ORC_REG_UNDEFINED
,
147 .bp_reg
= ORC_REG_UNDEFINED
,
148 .type
= ORC_TYPE_CALL
,
151 sec
= find_section_by_name(file
->elf
, ".orc_unwind");
153 WARN("file already has .orc_unwind section, skipping");
157 /* count the number of needed orcs */
159 for_each_sec(file
, sec
) {
164 sec_for_each_insn(file
, sec
, insn
) {
166 memcmp(&insn
->orc
, &prev_insn
->orc
,
167 sizeof(struct orc_entry
))) {
173 /* section terminator */
181 /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
182 sec
= elf_create_section(file
->elf
, ".orc_unwind_ip", sizeof(int), idx
);
186 ip_relasec
= elf_create_rela_section(file
->elf
, sec
);
190 /* create .orc_unwind section */
191 u_sec
= elf_create_section(file
->elf
, ".orc_unwind",
192 sizeof(struct orc_entry
), idx
);
194 /* populate sections */
196 for_each_sec(file
, sec
) {
201 sec_for_each_insn(file
, sec
, insn
) {
202 if (!prev_insn
|| memcmp(&insn
->orc
, &prev_insn
->orc
,
203 sizeof(struct orc_entry
))) {
205 if (create_orc_entry(file
->elf
, u_sec
, ip_relasec
, idx
,
206 insn
->sec
, insn
->offset
,
215 /* section terminator */
217 if (create_orc_entry(file
->elf
, u_sec
, ip_relasec
, idx
,
219 prev_insn
->offset
+ prev_insn
->len
,
227 if (elf_rebuild_rela_section(ip_relasec
))