Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/objtool/arch/x86/orc.c
49639 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
#include <linux/objtool_types.h>
3
#include <asm/orc_types.h>
4
5
#include <objtool/check.h>
6
#include <objtool/orc.h>
7
#include <objtool/warn.h>
8
9
int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn)
10
{
11
struct cfi_reg *bp = &cfi->regs[CFI_BP];
12
13
memset(orc, 0, sizeof(*orc));
14
15
if (!cfi) {
16
/*
17
* This is usually either unreachable nops/traps (which don't
18
* trigger unreachable instruction warnings), or
19
* STACK_FRAME_NON_STANDARD functions.
20
*/
21
orc->type = ORC_TYPE_UNDEFINED;
22
return 0;
23
}
24
25
switch (cfi->type) {
26
case UNWIND_HINT_TYPE_UNDEFINED:
27
orc->type = ORC_TYPE_UNDEFINED;
28
return 0;
29
case UNWIND_HINT_TYPE_END_OF_STACK:
30
orc->type = ORC_TYPE_END_OF_STACK;
31
return 0;
32
case UNWIND_HINT_TYPE_CALL:
33
orc->type = ORC_TYPE_CALL;
34
break;
35
case UNWIND_HINT_TYPE_REGS:
36
orc->type = ORC_TYPE_REGS;
37
break;
38
case UNWIND_HINT_TYPE_REGS_PARTIAL:
39
orc->type = ORC_TYPE_REGS_PARTIAL;
40
break;
41
default:
42
ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type);
43
return -1;
44
}
45
46
orc->signal = cfi->signal;
47
48
switch (cfi->cfa.base) {
49
case CFI_SP:
50
orc->sp_reg = ORC_REG_SP;
51
break;
52
case CFI_SP_INDIRECT:
53
orc->sp_reg = ORC_REG_SP_INDIRECT;
54
break;
55
case CFI_BP:
56
orc->sp_reg = ORC_REG_BP;
57
break;
58
case CFI_BP_INDIRECT:
59
orc->sp_reg = ORC_REG_BP_INDIRECT;
60
break;
61
case CFI_R10:
62
orc->sp_reg = ORC_REG_R10;
63
break;
64
case CFI_R13:
65
orc->sp_reg = ORC_REG_R13;
66
break;
67
case CFI_DI:
68
orc->sp_reg = ORC_REG_DI;
69
break;
70
case CFI_DX:
71
orc->sp_reg = ORC_REG_DX;
72
break;
73
default:
74
ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
75
return -1;
76
}
77
78
switch (bp->base) {
79
case CFI_UNDEFINED:
80
orc->bp_reg = ORC_REG_UNDEFINED;
81
break;
82
case CFI_CFA:
83
orc->bp_reg = ORC_REG_PREV_SP;
84
break;
85
case CFI_BP:
86
orc->bp_reg = ORC_REG_BP;
87
break;
88
default:
89
ERROR_INSN(insn, "unknown BP base reg %d", bp->base);
90
return -1;
91
}
92
93
orc->sp_offset = cfi->cfa.offset;
94
orc->bp_offset = bp->offset;
95
96
return 0;
97
}
98
99
int write_orc_entry(struct elf *elf, struct section *orc_sec,
100
struct section *ip_sec, unsigned int idx,
101
struct section *insn_sec, unsigned long insn_off,
102
struct orc_entry *o)
103
{
104
struct orc_entry *orc;
105
106
/* populate ORC data */
107
orc = (struct orc_entry *)orc_sec->data->d_buf + idx;
108
memcpy(orc, o, sizeof(*orc));
109
orc->sp_offset = bswap_if_needed(elf, orc->sp_offset);
110
orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);
111
112
/* populate reloc for ip */
113
if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
114
insn_sec, insn_off))
115
return -1;
116
117
return 0;
118
}
119
120
static const char *reg_name(unsigned int reg)
121
{
122
switch (reg) {
123
case ORC_REG_PREV_SP:
124
return "prevsp";
125
case ORC_REG_DX:
126
return "dx";
127
case ORC_REG_DI:
128
return "di";
129
case ORC_REG_BP:
130
return "bp";
131
case ORC_REG_SP:
132
return "sp";
133
case ORC_REG_R10:
134
return "r10";
135
case ORC_REG_R13:
136
return "r13";
137
case ORC_REG_BP_INDIRECT:
138
return "bp(ind)";
139
case ORC_REG_SP_INDIRECT:
140
return "sp(ind)";
141
default:
142
return "?";
143
}
144
}
145
146
static const char *orc_type_name(unsigned int type)
147
{
148
switch (type) {
149
case ORC_TYPE_UNDEFINED:
150
return "(und)";
151
case ORC_TYPE_END_OF_STACK:
152
return "end";
153
case ORC_TYPE_CALL:
154
return "call";
155
case ORC_TYPE_REGS:
156
return "regs";
157
case ORC_TYPE_REGS_PARTIAL:
158
return "regs (partial)";
159
default:
160
return "?";
161
}
162
}
163
164
static void print_reg(unsigned int reg, int offset)
165
{
166
if (reg == ORC_REG_BP_INDIRECT)
167
printf("(bp%+d)", offset);
168
else if (reg == ORC_REG_SP_INDIRECT)
169
printf("(sp)%+d", offset);
170
else if (reg == ORC_REG_UNDEFINED)
171
printf("(und)");
172
else
173
printf("%s%+d", reg_name(reg), offset);
174
}
175
176
void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i)
177
{
178
printf("type:%s", orc_type_name(orc[i].type));
179
180
printf(" sp:");
181
print_reg(orc[i].sp_reg, bswap_if_needed(dummy_elf, orc[i].sp_offset));
182
183
printf(" bp:");
184
print_reg(orc[i].bp_reg, bswap_if_needed(dummy_elf, orc[i].bp_offset));
185
186
printf(" signal:%d\n", orc[i].signal);
187
}
188
189