2 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
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.
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.
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/>.
25 int create_orc(struct objtool_file
*file
)
27 struct instruction
*insn
;
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
];
34 if (cfa
->base
== CFI_UNDEFINED
) {
35 orc
->sp_reg
= ORC_REG_UNDEFINED
;
41 orc
->sp_reg
= ORC_REG_SP
;
44 orc
->sp_reg
= ORC_REG_SP_INDIRECT
;
47 orc
->sp_reg
= ORC_REG_BP
;
50 orc
->sp_reg
= ORC_REG_BP_INDIRECT
;
53 orc
->sp_reg
= ORC_REG_R10
;
56 orc
->sp_reg
= ORC_REG_R13
;
59 orc
->sp_reg
= ORC_REG_DI
;
62 orc
->sp_reg
= ORC_REG_DX
;
65 WARN_FUNC("unknown CFA base reg %d",
66 insn
->sec
, insn
->offset
, cfa
->base
);
72 orc
->bp_reg
= ORC_REG_UNDEFINED
;
75 orc
->bp_reg
= ORC_REG_PREV_SP
;
78 orc
->bp_reg
= ORC_REG_BP
;
81 WARN_FUNC("unknown BP base reg %d",
82 insn
->sec
, insn
->offset
, bp
->base
);
86 orc
->sp_offset
= cfa
->offset
;
87 orc
->bp_offset
= bp
->offset
;
88 orc
->type
= insn
->state
.type
;
94 static int create_orc_entry(struct section
*u_sec
, struct section
*ip_relasec
,
95 unsigned int idx
, struct section
*insn_sec
,
96 unsigned long insn_off
, struct orc_entry
*o
)
98 struct orc_entry
*orc
;
101 if (!insn_sec
->sym
) {
102 WARN("missing symbol for section %s", insn_sec
->name
);
106 /* populate ORC data */
107 orc
= (struct orc_entry
*)u_sec
->data
->d_buf
+ idx
;
108 memcpy(orc
, o
, sizeof(*orc
));
110 /* populate rela for ip */
111 rela
= malloc(sizeof(*rela
));
116 memset(rela
, 0, sizeof(*rela
));
118 rela
->sym
= insn_sec
->sym
;
119 rela
->addend
= insn_off
;
120 rela
->type
= R_X86_64_PC32
;
121 rela
->offset
= idx
* sizeof(int);
123 list_add_tail(&rela
->list
, &ip_relasec
->rela_list
);
124 hash_add(ip_relasec
->rela_hash
, &rela
->hash
, rela
->offset
);
129 int create_orc_sections(struct objtool_file
*file
)
131 struct instruction
*insn
, *prev_insn
;
132 struct section
*sec
, *u_sec
, *ip_relasec
;
135 struct orc_entry empty
= {
136 .sp_reg
= ORC_REG_UNDEFINED
,
137 .bp_reg
= ORC_REG_UNDEFINED
,
138 .type
= ORC_TYPE_CALL
,
141 sec
= find_section_by_name(file
->elf
, ".orc_unwind");
143 WARN("file already has .orc_unwind section, skipping");
147 /* count the number of needed orcs */
149 for_each_sec(file
, sec
) {
154 sec_for_each_insn(file
, sec
, insn
) {
156 memcmp(&insn
->orc
, &prev_insn
->orc
,
157 sizeof(struct orc_entry
))) {
163 /* section terminator */
171 /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
172 sec
= elf_create_section(file
->elf
, ".orc_unwind_ip", sizeof(int), idx
);
176 ip_relasec
= elf_create_rela_section(file
->elf
, sec
);
180 /* create .orc_unwind section */
181 u_sec
= elf_create_section(file
->elf
, ".orc_unwind",
182 sizeof(struct orc_entry
), idx
);
184 /* populate sections */
186 for_each_sec(file
, sec
) {
191 sec_for_each_insn(file
, sec
, insn
) {
192 if (!prev_insn
|| memcmp(&insn
->orc
, &prev_insn
->orc
,
193 sizeof(struct orc_entry
))) {
195 if (create_orc_entry(u_sec
, ip_relasec
, idx
,
196 insn
->sec
, insn
->offset
,
205 /* section terminator */
207 if (create_orc_entry(u_sec
, ip_relasec
, idx
,
209 prev_insn
->offset
+ prev_insn
->len
,
217 if (elf_rebuild_rela_section(ip_relasec
))