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
*fp
= &cfi
->regs
[CFI_FP
];
13 struct cfi_reg
*ra
= &cfi
->regs
[CFI_RA
];
15 memset(orc
, 0, sizeof(*orc
));
19 * This is usually either unreachable nops/traps (which don't
20 * trigger unreachable instruction warnings), or
21 * STACK_FRAME_NON_STANDARD functions.
23 orc
->type
= ORC_TYPE_UNDEFINED
;
28 case UNWIND_HINT_TYPE_UNDEFINED
:
29 orc
->type
= ORC_TYPE_UNDEFINED
;
31 case UNWIND_HINT_TYPE_END_OF_STACK
:
32 orc
->type
= ORC_TYPE_END_OF_STACK
;
34 case UNWIND_HINT_TYPE_CALL
:
35 orc
->type
= ORC_TYPE_CALL
;
37 case UNWIND_HINT_TYPE_REGS
:
38 orc
->type
= ORC_TYPE_REGS
;
40 case UNWIND_HINT_TYPE_REGS_PARTIAL
:
41 orc
->type
= ORC_TYPE_REGS_PARTIAL
;
44 WARN_INSN(insn
, "unknown unwind hint type %d", cfi
->type
);
48 orc
->signal
= cfi
->signal
;
50 switch (cfi
->cfa
.base
) {
52 orc
->sp_reg
= ORC_REG_SP
;
55 orc
->sp_reg
= ORC_REG_FP
;
58 WARN_INSN(insn
, "unknown CFA base reg %d", cfi
->cfa
.base
);
64 orc
->fp_reg
= ORC_REG_UNDEFINED
;
68 orc
->fp_reg
= ORC_REG_PREV_SP
;
69 orc
->fp_offset
= fp
->offset
;
72 orc
->fp_reg
= ORC_REG_FP
;
75 WARN_INSN(insn
, "unknown FP base reg %d", fp
->base
);
81 orc
->ra_reg
= ORC_REG_UNDEFINED
;
85 orc
->ra_reg
= ORC_REG_PREV_SP
;
86 orc
->ra_offset
= ra
->offset
;
89 orc
->ra_reg
= ORC_REG_FP
;
92 WARN_INSN(insn
, "unknown RA base reg %d", ra
->base
);
96 orc
->sp_offset
= cfi
->cfa
.offset
;
101 int write_orc_entry(struct elf
*elf
, struct section
*orc_sec
,
102 struct section
*ip_sec
, unsigned int idx
,
103 struct section
*insn_sec
, unsigned long insn_off
,
106 struct orc_entry
*orc
;
108 /* populate ORC data */
109 orc
= (struct orc_entry
*)orc_sec
->data
->d_buf
+ idx
;
110 memcpy(orc
, o
, sizeof(*orc
));
112 /* populate reloc for ip */
113 if (!elf_init_reloc_text_sym(elf
, ip_sec
, idx
* sizeof(int), idx
,
120 static const char *reg_name(unsigned int reg
)
127 case ORC_REG_PREV_SP
:
134 static const char *orc_type_name(unsigned int type
)
137 case UNWIND_HINT_TYPE_CALL
:
139 case UNWIND_HINT_TYPE_REGS
:
141 case UNWIND_HINT_TYPE_REGS_PARTIAL
:
142 return "regs (partial)";
148 static void print_reg(unsigned int reg
, int offset
)
150 if (reg
== ORC_REG_UNDEFINED
)
153 printf("%s + %3d", reg_name(reg
), offset
);
157 void orc_print_dump(struct elf
*dummy_elf
, struct orc_entry
*orc
, int i
)
159 printf("type:%s", orc_type_name(orc
[i
].type
));
162 print_reg(orc
[i
].sp_reg
, orc
[i
].sp_offset
);
165 print_reg(orc
[i
].fp_reg
, orc
[i
].fp_offset
);
168 print_reg(orc
[i
].ra_reg
, orc
[i
].ra_offset
);
170 printf(" signal:%d\n", orc
[i
].signal
);