1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
9 #include <linux/objtool.h>
10 #include <asm/orc_types.h>
15 int create_orc(struct objtool_file
*file
)
17 struct instruction
*insn
;
19 for_each_insn(file
, insn
) {
20 struct orc_entry
*orc
= &insn
->orc
;
21 struct cfi_reg
*cfa
= &insn
->cfi
.cfa
;
22 struct cfi_reg
*bp
= &insn
->cfi
.regs
[CFI_BP
];
27 orc
->end
= insn
->cfi
.end
;
29 if (cfa
->base
== CFI_UNDEFINED
) {
30 orc
->sp_reg
= ORC_REG_UNDEFINED
;
36 orc
->sp_reg
= ORC_REG_SP
;
39 orc
->sp_reg
= ORC_REG_SP_INDIRECT
;
42 orc
->sp_reg
= ORC_REG_BP
;
45 orc
->sp_reg
= ORC_REG_BP_INDIRECT
;
48 orc
->sp_reg
= ORC_REG_R10
;
51 orc
->sp_reg
= ORC_REG_R13
;
54 orc
->sp_reg
= ORC_REG_DI
;
57 orc
->sp_reg
= ORC_REG_DX
;
60 WARN_FUNC("unknown CFA base reg %d",
61 insn
->sec
, insn
->offset
, cfa
->base
);
67 orc
->bp_reg
= ORC_REG_UNDEFINED
;
70 orc
->bp_reg
= ORC_REG_PREV_SP
;
73 orc
->bp_reg
= ORC_REG_BP
;
76 WARN_FUNC("unknown BP base reg %d",
77 insn
->sec
, insn
->offset
, bp
->base
);
81 orc
->sp_offset
= cfa
->offset
;
82 orc
->bp_offset
= bp
->offset
;
83 orc
->type
= insn
->cfi
.type
;
89 static int create_orc_entry(struct elf
*elf
, struct section
*u_sec
, struct section
*ip_relocsec
,
90 unsigned int idx
, struct section
*insn_sec
,
91 unsigned long insn_off
, struct orc_entry
*o
)
93 struct orc_entry
*orc
;
96 /* populate ORC data */
97 orc
= (struct orc_entry
*)u_sec
->data
->d_buf
+ idx
;
98 memcpy(orc
, o
, sizeof(*orc
));
100 /* populate reloc for ip */
101 reloc
= malloc(sizeof(*reloc
));
106 memset(reloc
, 0, sizeof(*reloc
));
108 insn_to_reloc_sym_addend(insn_sec
, insn_off
, reloc
);
110 WARN("missing symbol for insn at offset 0x%lx",
115 reloc
->type
= R_X86_64_PC32
;
116 reloc
->offset
= idx
* sizeof(int);
117 reloc
->sec
= ip_relocsec
;
119 elf_add_reloc(elf
, reloc
);
124 int create_orc_sections(struct objtool_file
*file
)
126 struct instruction
*insn
, *prev_insn
;
127 struct section
*sec
, *u_sec
, *ip_relocsec
;
130 struct orc_entry empty
= {
131 .sp_reg
= ORC_REG_UNDEFINED
,
132 .bp_reg
= ORC_REG_UNDEFINED
,
133 .type
= UNWIND_HINT_TYPE_CALL
,
136 sec
= find_section_by_name(file
->elf
, ".orc_unwind");
138 WARN("file already has .orc_unwind section, skipping");
142 /* count the number of needed orcs */
144 for_each_sec(file
, sec
) {
149 sec_for_each_insn(file
, sec
, insn
) {
151 memcmp(&insn
->orc
, &prev_insn
->orc
,
152 sizeof(struct orc_entry
))) {
158 /* section terminator */
166 /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
167 sec
= elf_create_section(file
->elf
, ".orc_unwind_ip", 0, sizeof(int), idx
);
171 ip_relocsec
= elf_create_reloc_section(file
->elf
, sec
, SHT_RELA
);
175 /* create .orc_unwind section */
176 u_sec
= elf_create_section(file
->elf
, ".orc_unwind", 0,
177 sizeof(struct orc_entry
), idx
);
179 /* populate sections */
181 for_each_sec(file
, sec
) {
186 sec_for_each_insn(file
, sec
, insn
) {
187 if (!prev_insn
|| memcmp(&insn
->orc
, &prev_insn
->orc
,
188 sizeof(struct orc_entry
))) {
190 if (create_orc_entry(file
->elf
, u_sec
, ip_relocsec
, idx
,
191 insn
->sec
, insn
->offset
,
200 /* section terminator */
202 if (create_orc_entry(file
->elf
, u_sec
, ip_relocsec
, idx
,
204 prev_insn
->offset
+ prev_insn
->len
,
212 if (elf_rebuild_reloc_section(file
->elf
, ip_relocsec
))