1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include <linux/objtool_types.h>
3 #include <asm/orc_types.h>
5 #include <objtool/check.h>
6 #include <objtool/orc.h>
7 #include <objtool/warn.h>
8 #include <objtool/endianness.h>
10 int init_orc_entry(struct orc_entry
*orc
, struct cfi_state
*cfi
, struct instruction
*insn
)
12 struct cfi_reg
*bp
= &cfi
->regs
[CFI_BP
];
14 memset(orc
, 0, sizeof(*orc
));
18 * This is usually either unreachable nops/traps (which don't
19 * trigger unreachable instruction warnings), or
20 * STACK_FRAME_NON_STANDARD functions.
22 orc
->type
= ORC_TYPE_UNDEFINED
;
27 case UNWIND_HINT_TYPE_UNDEFINED
:
28 orc
->type
= ORC_TYPE_UNDEFINED
;
30 case UNWIND_HINT_TYPE_END_OF_STACK
:
31 orc
->type
= ORC_TYPE_END_OF_STACK
;
33 case UNWIND_HINT_TYPE_CALL
:
34 orc
->type
= ORC_TYPE_CALL
;
36 case UNWIND_HINT_TYPE_REGS
:
37 orc
->type
= ORC_TYPE_REGS
;
39 case UNWIND_HINT_TYPE_REGS_PARTIAL
:
40 orc
->type
= ORC_TYPE_REGS_PARTIAL
;
43 WARN_INSN(insn
, "unknown unwind hint type %d", cfi
->type
);
47 orc
->signal
= cfi
->signal
;
49 switch (cfi
->cfa
.base
) {
51 orc
->sp_reg
= ORC_REG_SP
;
54 orc
->sp_reg
= ORC_REG_SP_INDIRECT
;
57 orc
->sp_reg
= ORC_REG_BP
;
60 orc
->sp_reg
= ORC_REG_BP_INDIRECT
;
63 orc
->sp_reg
= ORC_REG_R10
;
66 orc
->sp_reg
= ORC_REG_R13
;
69 orc
->sp_reg
= ORC_REG_DI
;
72 orc
->sp_reg
= ORC_REG_DX
;
75 WARN_INSN(insn
, "unknown CFA base reg %d", cfi
->cfa
.base
);
81 orc
->bp_reg
= ORC_REG_UNDEFINED
;
84 orc
->bp_reg
= ORC_REG_PREV_SP
;
87 orc
->bp_reg
= ORC_REG_BP
;
90 WARN_INSN(insn
, "unknown BP base reg %d", bp
->base
);
94 orc
->sp_offset
= cfi
->cfa
.offset
;
95 orc
->bp_offset
= bp
->offset
;
100 int write_orc_entry(struct elf
*elf
, struct section
*orc_sec
,
101 struct section
*ip_sec
, unsigned int idx
,
102 struct section
*insn_sec
, unsigned long insn_off
,
105 struct orc_entry
*orc
;
107 /* populate ORC data */
108 orc
= (struct orc_entry
*)orc_sec
->data
->d_buf
+ idx
;
109 memcpy(orc
, o
, sizeof(*orc
));
110 orc
->sp_offset
= bswap_if_needed(elf
, orc
->sp_offset
);
111 orc
->bp_offset
= bswap_if_needed(elf
, orc
->bp_offset
);
113 /* populate reloc for ip */
114 if (!elf_init_reloc_text_sym(elf
, ip_sec
, idx
* sizeof(int), idx
,
121 static const char *reg_name(unsigned int reg
)
124 case ORC_REG_PREV_SP
:
138 case ORC_REG_BP_INDIRECT
:
140 case ORC_REG_SP_INDIRECT
:
147 static const char *orc_type_name(unsigned int type
)
150 case ORC_TYPE_UNDEFINED
:
152 case ORC_TYPE_END_OF_STACK
:
158 case ORC_TYPE_REGS_PARTIAL
:
159 return "regs (partial)";
165 static void print_reg(unsigned int reg
, int offset
)
167 if (reg
== ORC_REG_BP_INDIRECT
)
168 printf("(bp%+d)", offset
);
169 else if (reg
== ORC_REG_SP_INDIRECT
)
170 printf("(sp)%+d", offset
);
171 else if (reg
== ORC_REG_UNDEFINED
)
174 printf("%s%+d", reg_name(reg
), offset
);
177 void orc_print_dump(struct elf
*dummy_elf
, struct orc_entry
*orc
, int i
)
179 printf("type:%s", orc_type_name(orc
[i
].type
));
182 print_reg(orc
[i
].sp_reg
, bswap_if_needed(dummy_elf
, orc
[i
].sp_offset
));
185 print_reg(orc
[i
].bp_reg
, bswap_if_needed(dummy_elf
, orc
[i
].bp_offset
));
187 printf(" signal:%d\n", orc
[i
].signal
);