Annotation of /trunk/kernel-alx/patches-4.9/0205-4.9.106-all-fixes.patch
Parent Directory | Revision Log
Revision 3182 -
(hide annotations)
(download)
Wed Aug 8 14:17:34 2018 UTC (5 years, 10 months ago) by niro
File size: 382694 byte(s)
Wed Aug 8 14:17:34 2018 UTC (5 years, 10 months ago) by niro
File size: 382694 byte(s)
-linux-4.9.106
1 | niro | 3182 | diff --git a/Makefile b/Makefile |
2 | index 7d06dba3fde8..48d87e3a36c1 100644 | ||
3 | --- a/Makefile | ||
4 | +++ b/Makefile | ||
5 | @@ -1,6 +1,6 @@ | ||
6 | VERSION = 4 | ||
7 | PATCHLEVEL = 9 | ||
8 | -SUBLEVEL = 105 | ||
9 | +SUBLEVEL = 106 | ||
10 | EXTRAVERSION = | ||
11 | NAME = Roaring Lionus | ||
12 | |||
13 | diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile | ||
14 | index 34b3fa2889d1..9e32d40d71bd 100644 | ||
15 | --- a/arch/x86/crypto/Makefile | ||
16 | +++ b/arch/x86/crypto/Makefile | ||
17 | @@ -2,6 +2,8 @@ | ||
18 | # Arch-specific CryptoAPI modules. | ||
19 | # | ||
20 | |||
21 | +OBJECT_FILES_NON_STANDARD := y | ||
22 | + | ||
23 | avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no) | ||
24 | avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ | ||
25 | $(comma)4)$(comma)%ymm2,yes,no) | ||
26 | diff --git a/arch/x86/crypto/sha1-mb/Makefile b/arch/x86/crypto/sha1-mb/Makefile | ||
27 | index 2f8756375df5..2e14acc3da25 100644 | ||
28 | --- a/arch/x86/crypto/sha1-mb/Makefile | ||
29 | +++ b/arch/x86/crypto/sha1-mb/Makefile | ||
30 | @@ -2,6 +2,8 @@ | ||
31 | # Arch-specific CryptoAPI modules. | ||
32 | # | ||
33 | |||
34 | +OBJECT_FILES_NON_STANDARD := y | ||
35 | + | ||
36 | avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ | ||
37 | $(comma)4)$(comma)%ymm2,yes,no) | ||
38 | ifeq ($(avx2_supported),yes) | ||
39 | diff --git a/arch/x86/crypto/sha256-mb/Makefile b/arch/x86/crypto/sha256-mb/Makefile | ||
40 | index 41089e7c400c..45b4fca6c4a8 100644 | ||
41 | --- a/arch/x86/crypto/sha256-mb/Makefile | ||
42 | +++ b/arch/x86/crypto/sha256-mb/Makefile | ||
43 | @@ -2,6 +2,8 @@ | ||
44 | # Arch-specific CryptoAPI modules. | ||
45 | # | ||
46 | |||
47 | +OBJECT_FILES_NON_STANDARD := y | ||
48 | + | ||
49 | avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\ | ||
50 | $(comma)4)$(comma)%ymm2,yes,no) | ||
51 | ifeq ($(avx2_supported),yes) | ||
52 | diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h | ||
53 | new file mode 100644 | ||
54 | index 000000000000..7dc777a6cb40 | ||
55 | --- /dev/null | ||
56 | +++ b/arch/x86/include/asm/orc_types.h | ||
57 | @@ -0,0 +1,107 @@ | ||
58 | +/* | ||
59 | + * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
60 | + * | ||
61 | + * This program is free software; you can redistribute it and/or | ||
62 | + * modify it under the terms of the GNU General Public License | ||
63 | + * as published by the Free Software Foundation; either version 2 | ||
64 | + * of the License, or (at your option) any later version. | ||
65 | + * | ||
66 | + * This program is distributed in the hope that it will be useful, | ||
67 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
68 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
69 | + * GNU General Public License for more details. | ||
70 | + * | ||
71 | + * You should have received a copy of the GNU General Public License | ||
72 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
73 | + */ | ||
74 | + | ||
75 | +#ifndef _ORC_TYPES_H | ||
76 | +#define _ORC_TYPES_H | ||
77 | + | ||
78 | +#include <linux/types.h> | ||
79 | +#include <linux/compiler.h> | ||
80 | + | ||
81 | +/* | ||
82 | + * The ORC_REG_* registers are base registers which are used to find other | ||
83 | + * registers on the stack. | ||
84 | + * | ||
85 | + * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the | ||
86 | + * address of the previous frame: the caller's SP before it called the current | ||
87 | + * function. | ||
88 | + * | ||
89 | + * ORC_REG_UNDEFINED means the corresponding register's value didn't change in | ||
90 | + * the current frame. | ||
91 | + * | ||
92 | + * The most commonly used base registers are SP and BP -- which the previous SP | ||
93 | + * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is | ||
94 | + * usually based on. | ||
95 | + * | ||
96 | + * The rest of the base registers are needed for special cases like entry code | ||
97 | + * and GCC realigned stacks. | ||
98 | + */ | ||
99 | +#define ORC_REG_UNDEFINED 0 | ||
100 | +#define ORC_REG_PREV_SP 1 | ||
101 | +#define ORC_REG_DX 2 | ||
102 | +#define ORC_REG_DI 3 | ||
103 | +#define ORC_REG_BP 4 | ||
104 | +#define ORC_REG_SP 5 | ||
105 | +#define ORC_REG_R10 6 | ||
106 | +#define ORC_REG_R13 7 | ||
107 | +#define ORC_REG_BP_INDIRECT 8 | ||
108 | +#define ORC_REG_SP_INDIRECT 9 | ||
109 | +#define ORC_REG_MAX 15 | ||
110 | + | ||
111 | +/* | ||
112 | + * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the | ||
113 | + * caller's SP right before it made the call). Used for all callable | ||
114 | + * functions, i.e. all C code and all callable asm functions. | ||
115 | + * | ||
116 | + * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points | ||
117 | + * to a fully populated pt_regs from a syscall, interrupt, or exception. | ||
118 | + * | ||
119 | + * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset | ||
120 | + * points to the iret return frame. | ||
121 | + * | ||
122 | + * The UNWIND_HINT macros are used only for the unwind_hint struct. They | ||
123 | + * aren't used in struct orc_entry due to size and complexity constraints. | ||
124 | + * Objtool converts them to real types when it converts the hints to orc | ||
125 | + * entries. | ||
126 | + */ | ||
127 | +#define ORC_TYPE_CALL 0 | ||
128 | +#define ORC_TYPE_REGS 1 | ||
129 | +#define ORC_TYPE_REGS_IRET 2 | ||
130 | +#define UNWIND_HINT_TYPE_SAVE 3 | ||
131 | +#define UNWIND_HINT_TYPE_RESTORE 4 | ||
132 | + | ||
133 | +#ifndef __ASSEMBLY__ | ||
134 | +/* | ||
135 | + * This struct is more or less a vastly simplified version of the DWARF Call | ||
136 | + * Frame Information standard. It contains only the necessary parts of DWARF | ||
137 | + * CFI, simplified for ease of access by the in-kernel unwinder. It tells the | ||
138 | + * unwinder how to find the previous SP and BP (and sometimes entry regs) on | ||
139 | + * the stack for a given code address. Each instance of the struct corresponds | ||
140 | + * to one or more code locations. | ||
141 | + */ | ||
142 | +struct orc_entry { | ||
143 | + s16 sp_offset; | ||
144 | + s16 bp_offset; | ||
145 | + unsigned sp_reg:4; | ||
146 | + unsigned bp_reg:4; | ||
147 | + unsigned type:2; | ||
148 | +}; | ||
149 | + | ||
150 | +/* | ||
151 | + * This struct is used by asm and inline asm code to manually annotate the | ||
152 | + * location of registers on the stack for the ORC unwinder. | ||
153 | + * | ||
154 | + * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. | ||
155 | + */ | ||
156 | +struct unwind_hint { | ||
157 | + u32 ip; | ||
158 | + s16 sp_offset; | ||
159 | + u8 sp_reg; | ||
160 | + u8 type; | ||
161 | +}; | ||
162 | +#endif /* __ASSEMBLY__ */ | ||
163 | + | ||
164 | +#endif /* _ORC_TYPES_H */ | ||
165 | diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h | ||
166 | new file mode 100644 | ||
167 | index 000000000000..5e02b11c9b86 | ||
168 | --- /dev/null | ||
169 | +++ b/arch/x86/include/asm/unwind_hints.h | ||
170 | @@ -0,0 +1,103 @@ | ||
171 | +#ifndef _ASM_X86_UNWIND_HINTS_H | ||
172 | +#define _ASM_X86_UNWIND_HINTS_H | ||
173 | + | ||
174 | +#include "orc_types.h" | ||
175 | + | ||
176 | +#ifdef __ASSEMBLY__ | ||
177 | + | ||
178 | +/* | ||
179 | + * In asm, there are two kinds of code: normal C-type callable functions and | ||
180 | + * the rest. The normal callable functions can be called by other code, and | ||
181 | + * don't do anything unusual with the stack. Such normal callable functions | ||
182 | + * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this | ||
183 | + * category. In this case, no special debugging annotations are needed because | ||
184 | + * objtool can automatically generate the ORC data for the ORC unwinder to read | ||
185 | + * at runtime. | ||
186 | + * | ||
187 | + * Anything which doesn't fall into the above category, such as syscall and | ||
188 | + * interrupt handlers, tends to not be called directly by other functions, and | ||
189 | + * often does unusual non-C-function-type things with the stack pointer. Such | ||
190 | + * code needs to be annotated such that objtool can understand it. The | ||
191 | + * following CFI hint macros are for this type of code. | ||
192 | + * | ||
193 | + * These macros provide hints to objtool about the state of the stack at each | ||
194 | + * instruction. Objtool starts from the hints and follows the code flow, | ||
195 | + * making automatic CFI adjustments when it sees pushes and pops, filling out | ||
196 | + * the debuginfo as necessary. It will also warn if it sees any | ||
197 | + * inconsistencies. | ||
198 | + */ | ||
199 | +.macro UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=0 type=ORC_TYPE_CALL | ||
200 | +#ifdef CONFIG_STACK_VALIDATION | ||
201 | +.Lunwind_hint_ip_\@: | ||
202 | + .pushsection .discard.unwind_hints | ||
203 | + /* struct unwind_hint */ | ||
204 | + .long .Lunwind_hint_ip_\@ - . | ||
205 | + .short \sp_offset | ||
206 | + .byte \sp_reg | ||
207 | + .byte \type | ||
208 | + .popsection | ||
209 | +#endif | ||
210 | +.endm | ||
211 | + | ||
212 | +.macro UNWIND_HINT_EMPTY | ||
213 | + UNWIND_HINT sp_reg=ORC_REG_UNDEFINED | ||
214 | +.endm | ||
215 | + | ||
216 | +.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 iret=0 | ||
217 | + .if \base == %rsp && \indirect | ||
218 | + .set sp_reg, ORC_REG_SP_INDIRECT | ||
219 | + .elseif \base == %rsp | ||
220 | + .set sp_reg, ORC_REG_SP | ||
221 | + .elseif \base == %rbp | ||
222 | + .set sp_reg, ORC_REG_BP | ||
223 | + .elseif \base == %rdi | ||
224 | + .set sp_reg, ORC_REG_DI | ||
225 | + .elseif \base == %rdx | ||
226 | + .set sp_reg, ORC_REG_DX | ||
227 | + .elseif \base == %r10 | ||
228 | + .set sp_reg, ORC_REG_R10 | ||
229 | + .else | ||
230 | + .error "UNWIND_HINT_REGS: bad base register" | ||
231 | + .endif | ||
232 | + | ||
233 | + .set sp_offset, \offset | ||
234 | + | ||
235 | + .if \iret | ||
236 | + .set type, ORC_TYPE_REGS_IRET | ||
237 | + .elseif \extra == 0 | ||
238 | + .set type, ORC_TYPE_REGS_IRET | ||
239 | + .set sp_offset, \offset + (16*8) | ||
240 | + .else | ||
241 | + .set type, ORC_TYPE_REGS | ||
242 | + .endif | ||
243 | + | ||
244 | + UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type | ||
245 | +.endm | ||
246 | + | ||
247 | +.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 | ||
248 | + UNWIND_HINT_REGS base=\base offset=\offset iret=1 | ||
249 | +.endm | ||
250 | + | ||
251 | +.macro UNWIND_HINT_FUNC sp_offset=8 | ||
252 | + UNWIND_HINT sp_offset=\sp_offset | ||
253 | +.endm | ||
254 | + | ||
255 | +#else /* !__ASSEMBLY__ */ | ||
256 | + | ||
257 | +#define UNWIND_HINT(sp_reg, sp_offset, type) \ | ||
258 | + "987: \n\t" \ | ||
259 | + ".pushsection .discard.unwind_hints\n\t" \ | ||
260 | + /* struct unwind_hint */ \ | ||
261 | + ".long 987b - .\n\t" \ | ||
262 | + ".short " __stringify(sp_offset) "\n\t" \ | ||
263 | + ".byte " __stringify(sp_reg) "\n\t" \ | ||
264 | + ".byte " __stringify(type) "\n\t" \ | ||
265 | + ".popsection\n\t" | ||
266 | + | ||
267 | +#define UNWIND_HINT_SAVE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_SAVE) | ||
268 | + | ||
269 | +#define UNWIND_HINT_RESTORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_RESTORE) | ||
270 | + | ||
271 | +#endif /* __ASSEMBLY__ */ | ||
272 | + | ||
273 | +#endif /* _ASM_X86_UNWIND_HINTS_H */ | ||
274 | diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile | ||
275 | index 79076d75bdbf..4c9c61517613 100644 | ||
276 | --- a/arch/x86/kernel/Makefile | ||
277 | +++ b/arch/x86/kernel/Makefile | ||
278 | @@ -29,6 +29,7 @@ OBJECT_FILES_NON_STANDARD_head_$(BITS).o := y | ||
279 | OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o := y | ||
280 | OBJECT_FILES_NON_STANDARD_mcount_$(BITS).o := y | ||
281 | OBJECT_FILES_NON_STANDARD_test_nx.o := y | ||
282 | +OBJECT_FILES_NON_STANDARD_paravirt_patch_$(BITS).o := y | ||
283 | |||
284 | # If instrumentation of this dir is enabled, boot hangs during first second. | ||
285 | # Probably could be more selective here, but note that files related to irqs, | ||
286 | diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile | ||
287 | index 26b78d86f25a..85a9e17e0dbc 100644 | ||
288 | --- a/arch/x86/kernel/acpi/Makefile | ||
289 | +++ b/arch/x86/kernel/acpi/Makefile | ||
290 | @@ -1,3 +1,5 @@ | ||
291 | +OBJECT_FILES_NON_STANDARD_wakeup_$(BITS).o := y | ||
292 | + | ||
293 | obj-$(CONFIG_ACPI) += boot.o | ||
294 | obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o | ||
295 | obj-$(CONFIG_ACPI_APEI) += apei.o | ||
296 | diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c | ||
297 | index fa671b90c374..1808a9cc7701 100644 | ||
298 | --- a/arch/x86/kernel/kprobes/opt.c | ||
299 | +++ b/arch/x86/kernel/kprobes/opt.c | ||
300 | @@ -28,6 +28,7 @@ | ||
301 | #include <linux/kdebug.h> | ||
302 | #include <linux/kallsyms.h> | ||
303 | #include <linux/ftrace.h> | ||
304 | +#include <linux/frame.h> | ||
305 | |||
306 | #include <asm/text-patching.h> | ||
307 | #include <asm/cacheflush.h> | ||
308 | @@ -91,6 +92,7 @@ static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val) | ||
309 | } | ||
310 | |||
311 | asm ( | ||
312 | + "optprobe_template_func:\n" | ||
313 | ".global optprobe_template_entry\n" | ||
314 | "optprobe_template_entry:\n" | ||
315 | #ifdef CONFIG_X86_64 | ||
316 | @@ -128,7 +130,12 @@ asm ( | ||
317 | " popf\n" | ||
318 | #endif | ||
319 | ".global optprobe_template_end\n" | ||
320 | - "optprobe_template_end:\n"); | ||
321 | + "optprobe_template_end:\n" | ||
322 | + ".type optprobe_template_func, @function\n" | ||
323 | + ".size optprobe_template_func, .-optprobe_template_func\n"); | ||
324 | + | ||
325 | +void optprobe_template_func(void); | ||
326 | +STACK_FRAME_NON_STANDARD(optprobe_template_func); | ||
327 | |||
328 | #define TMPL_MOVE_IDX \ | ||
329 | ((long)&optprobe_template_val - (long)&optprobe_template_entry) | ||
330 | diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c | ||
331 | index 03f21dbfaa9d..4a12362a194a 100644 | ||
332 | --- a/arch/x86/kernel/reboot.c | ||
333 | +++ b/arch/x86/kernel/reboot.c | ||
334 | @@ -9,6 +9,7 @@ | ||
335 | #include <linux/sched.h> | ||
336 | #include <linux/tboot.h> | ||
337 | #include <linux/delay.h> | ||
338 | +#include <linux/frame.h> | ||
339 | #include <acpi/reboot.h> | ||
340 | #include <asm/io.h> | ||
341 | #include <asm/apic.h> | ||
342 | @@ -127,6 +128,7 @@ void __noreturn machine_real_restart(unsigned int type) | ||
343 | #ifdef CONFIG_APM_MODULE | ||
344 | EXPORT_SYMBOL(machine_real_restart); | ||
345 | #endif | ||
346 | +STACK_FRAME_NON_STANDARD(machine_real_restart); | ||
347 | |||
348 | /* | ||
349 | * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot | ||
350 | diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S | ||
351 | index c7194e97c3d4..4ef267fb635a 100644 | ||
352 | --- a/arch/x86/kernel/vmlinux.lds.S | ||
353 | +++ b/arch/x86/kernel/vmlinux.lds.S | ||
354 | @@ -353,6 +353,7 @@ SECTIONS | ||
355 | /DISCARD/ : { | ||
356 | *(.eh_frame) | ||
357 | *(__func_stack_frame_non_standard) | ||
358 | + *(__unreachable) | ||
359 | } | ||
360 | } | ||
361 | |||
362 | diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c | ||
363 | index a27f9e442ffc..c4cd1280ac3e 100644 | ||
364 | --- a/arch/x86/kvm/svm.c | ||
365 | +++ b/arch/x86/kvm/svm.c | ||
366 | @@ -36,6 +36,7 @@ | ||
367 | #include <linux/slab.h> | ||
368 | #include <linux/amd-iommu.h> | ||
369 | #include <linux/hashtable.h> | ||
370 | +#include <linux/frame.h> | ||
371 | |||
372 | #include <asm/apic.h> | ||
373 | #include <asm/perf_event.h> | ||
374 | @@ -5111,6 +5112,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) | ||
375 | |||
376 | mark_all_clean(svm->vmcb); | ||
377 | } | ||
378 | +STACK_FRAME_NON_STANDARD(svm_vcpu_run); | ||
379 | |||
380 | static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) | ||
381 | { | ||
382 | diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c | ||
383 | index 2827a9622d97..4a66a620fc17 100644 | ||
384 | --- a/arch/x86/kvm/vmx.c | ||
385 | +++ b/arch/x86/kvm/vmx.c | ||
386 | @@ -33,6 +33,7 @@ | ||
387 | #include <linux/slab.h> | ||
388 | #include <linux/tboot.h> | ||
389 | #include <linux/hrtimer.h> | ||
390 | +#include <linux/frame.h> | ||
391 | #include <linux/nospec.h> | ||
392 | #include "kvm_cache_regs.h" | ||
393 | #include "x86.h" | ||
394 | @@ -8698,6 +8699,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu) | ||
395 | ); | ||
396 | } | ||
397 | } | ||
398 | +STACK_FRAME_NON_STANDARD(vmx_handle_external_intr); | ||
399 | |||
400 | static bool vmx_has_emulated_msr(int index) | ||
401 | { | ||
402 | @@ -9138,6 +9140,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) | ||
403 | vmx_recover_nmi_blocking(vmx); | ||
404 | vmx_complete_interrupts(vmx); | ||
405 | } | ||
406 | +STACK_FRAME_NON_STANDARD(vmx_vcpu_run); | ||
407 | |||
408 | static void vmx_load_vmcs01(struct kvm_vcpu *vcpu) | ||
409 | { | ||
410 | diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S | ||
411 | index c81556409bbb..10ffa7e8519f 100644 | ||
412 | --- a/arch/x86/lib/msr-reg.S | ||
413 | +++ b/arch/x86/lib/msr-reg.S | ||
414 | @@ -13,14 +13,14 @@ | ||
415 | .macro op_safe_regs op | ||
416 | ENTRY(\op\()_safe_regs) | ||
417 | pushq %rbx | ||
418 | - pushq %rbp | ||
419 | + pushq %r12 | ||
420 | movq %rdi, %r10 /* Save pointer */ | ||
421 | xorl %r11d, %r11d /* Return value */ | ||
422 | movl (%rdi), %eax | ||
423 | movl 4(%rdi), %ecx | ||
424 | movl 8(%rdi), %edx | ||
425 | movl 12(%rdi), %ebx | ||
426 | - movl 20(%rdi), %ebp | ||
427 | + movl 20(%rdi), %r12d | ||
428 | movl 24(%rdi), %esi | ||
429 | movl 28(%rdi), %edi | ||
430 | 1: \op | ||
431 | @@ -29,10 +29,10 @@ ENTRY(\op\()_safe_regs) | ||
432 | movl %ecx, 4(%r10) | ||
433 | movl %edx, 8(%r10) | ||
434 | movl %ebx, 12(%r10) | ||
435 | - movl %ebp, 20(%r10) | ||
436 | + movl %r12d, 20(%r10) | ||
437 | movl %esi, 24(%r10) | ||
438 | movl %edi, 28(%r10) | ||
439 | - popq %rbp | ||
440 | + popq %r12 | ||
441 | popq %rbx | ||
442 | ret | ||
443 | 3: | ||
444 | diff --git a/arch/x86/net/Makefile b/arch/x86/net/Makefile | ||
445 | index 90568c33ddb0..fefb4b619598 100644 | ||
446 | --- a/arch/x86/net/Makefile | ||
447 | +++ b/arch/x86/net/Makefile | ||
448 | @@ -1,4 +1,6 @@ | ||
449 | # | ||
450 | # Arch-specific network modules | ||
451 | # | ||
452 | +OBJECT_FILES_NON_STANDARD_bpf_jit.o += y | ||
453 | + | ||
454 | obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o | ||
455 | diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile | ||
456 | index 066619b0700c..7a255022933e 100644 | ||
457 | --- a/arch/x86/platform/efi/Makefile | ||
458 | +++ b/arch/x86/platform/efi/Makefile | ||
459 | @@ -1,4 +1,5 @@ | ||
460 | OBJECT_FILES_NON_STANDARD_efi_thunk_$(BITS).o := y | ||
461 | +OBJECT_FILES_NON_STANDARD_efi_stub_$(BITS).o := y | ||
462 | |||
463 | obj-$(CONFIG_EFI) += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o | ||
464 | obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o | ||
465 | diff --git a/arch/x86/power/Makefile b/arch/x86/power/Makefile | ||
466 | index a6a198c33623..05041871ac90 100644 | ||
467 | --- a/arch/x86/power/Makefile | ||
468 | +++ b/arch/x86/power/Makefile | ||
469 | @@ -1,3 +1,5 @@ | ||
470 | +OBJECT_FILES_NON_STANDARD_hibernate_asm_$(BITS).o := y | ||
471 | + | ||
472 | # __restore_processor_state() restores %gs after S3 resume and so should not | ||
473 | # itself be stack-protected | ||
474 | nostackp := $(call cc-option, -fno-stack-protector) | ||
475 | diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile | ||
476 | index e47e52787d32..4a54059f42ba 100644 | ||
477 | --- a/arch/x86/xen/Makefile | ||
478 | +++ b/arch/x86/xen/Makefile | ||
479 | @@ -1,3 +1,6 @@ | ||
480 | +OBJECT_FILES_NON_STANDARD_xen-asm_$(BITS).o := y | ||
481 | +OBJECT_FILES_NON_STANDARD_xen-pvh.o := y | ||
482 | + | ||
483 | ifdef CONFIG_FUNCTION_TRACER | ||
484 | # Do not profile debug and lowlevel utilities | ||
485 | CFLAGS_REMOVE_spinlock.o = -pg | ||
486 | diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c | ||
487 | index 081437b5f381..e3a3f5a64884 100644 | ||
488 | --- a/arch/x86/xen/enlighten.c | ||
489 | +++ b/arch/x86/xen/enlighten.c | ||
490 | @@ -75,6 +75,7 @@ | ||
491 | #include <asm/mwait.h> | ||
492 | #include <asm/pci_x86.h> | ||
493 | #include <asm/cpu.h> | ||
494 | +#include <asm/unwind_hints.h> | ||
495 | |||
496 | #ifdef CONFIG_ACPI | ||
497 | #include <linux/acpi.h> | ||
498 | @@ -1452,10 +1453,12 @@ static void __ref xen_setup_gdt(int cpu) | ||
499 | * GDT. The new GDT has __KERNEL_CS with CS.L = 1 | ||
500 | * and we are jumping to reload it. | ||
501 | */ | ||
502 | - asm volatile ("pushq %0\n" | ||
503 | + asm volatile (UNWIND_HINT_SAVE | ||
504 | + "pushq %0\n" | ||
505 | "leaq 1f(%%rip),%0\n" | ||
506 | "pushq %0\n" | ||
507 | "lretq\n" | ||
508 | + UNWIND_HINT_RESTORE | ||
509 | "1:\n" | ||
510 | : "=&r" (dummy) : "0" (__KERNEL_CS)); | ||
511 | |||
512 | diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h | ||
513 | index a1b1de17455c..2214b2f9c73c 100644 | ||
514 | --- a/include/linux/compiler-gcc.h | ||
515 | +++ b/include/linux/compiler-gcc.h | ||
516 | @@ -203,6 +203,17 @@ | ||
517 | #endif | ||
518 | #endif | ||
519 | |||
520 | +#ifdef CONFIG_STACK_VALIDATION | ||
521 | +#define annotate_unreachable() ({ \ | ||
522 | + asm("1:\t\n" \ | ||
523 | + ".pushsection __unreachable, \"a\"\t\n" \ | ||
524 | + ".long 1b\t\n" \ | ||
525 | + ".popsection\t\n"); \ | ||
526 | +}) | ||
527 | +#else | ||
528 | +#define annotate_unreachable() | ||
529 | +#endif | ||
530 | + | ||
531 | /* | ||
532 | * Mark a position in code as unreachable. This can be used to | ||
533 | * suppress control flow warnings after asm blocks that transfer | ||
534 | @@ -212,7 +223,8 @@ | ||
535 | * this in the preprocessor, but we can live with this because they're | ||
536 | * unreleased. Really, we need to have autoconf for the kernel. | ||
537 | */ | ||
538 | -#define unreachable() __builtin_unreachable() | ||
539 | +#define unreachable() \ | ||
540 | + do { annotate_unreachable(); __builtin_unreachable(); } while (0) | ||
541 | |||
542 | /* Mark a function definition as prohibited from being cloned. */ | ||
543 | #define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) | ||
544 | diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c | ||
545 | index 561675589511..f5ab72ebda11 100644 | ||
546 | --- a/kernel/kexec_core.c | ||
547 | +++ b/kernel/kexec_core.c | ||
548 | @@ -38,6 +38,7 @@ | ||
549 | #include <linux/syscore_ops.h> | ||
550 | #include <linux/compiler.h> | ||
551 | #include <linux/hugetlb.h> | ||
552 | +#include <linux/frame.h> | ||
553 | |||
554 | #include <asm/page.h> | ||
555 | #include <asm/sections.h> | ||
556 | @@ -878,7 +879,7 @@ int kexec_load_disabled; | ||
557 | * only when panic_cpu holds the current CPU number; this is the only CPU | ||
558 | * which processes crash_kexec routines. | ||
559 | */ | ||
560 | -void __crash_kexec(struct pt_regs *regs) | ||
561 | +void __noclone __crash_kexec(struct pt_regs *regs) | ||
562 | { | ||
563 | /* Take the kexec_mutex here to prevent sys_kexec_load | ||
564 | * running on one cpu from replacing the crash kernel | ||
565 | @@ -900,6 +901,7 @@ void __crash_kexec(struct pt_regs *regs) | ||
566 | mutex_unlock(&kexec_mutex); | ||
567 | } | ||
568 | } | ||
569 | +STACK_FRAME_NON_STANDARD(__crash_kexec); | ||
570 | |||
571 | void crash_kexec(struct pt_regs *regs) | ||
572 | { | ||
573 | diff --git a/tools/arch/arm/include/uapi/asm/kvm.h b/tools/arch/arm/include/uapi/asm/kvm.h | ||
574 | index a2b3eb313a25..0b8cf31d8416 100644 | ||
575 | --- a/tools/arch/arm/include/uapi/asm/kvm.h | ||
576 | +++ b/tools/arch/arm/include/uapi/asm/kvm.h | ||
577 | @@ -84,6 +84,13 @@ struct kvm_regs { | ||
578 | #define KVM_VGIC_V2_DIST_SIZE 0x1000 | ||
579 | #define KVM_VGIC_V2_CPU_SIZE 0x2000 | ||
580 | |||
581 | +/* Supported VGICv3 address types */ | ||
582 | +#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 | ||
583 | +#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 | ||
584 | + | ||
585 | +#define KVM_VGIC_V3_DIST_SIZE SZ_64K | ||
586 | +#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) | ||
587 | + | ||
588 | #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ | ||
589 | #define KVM_ARM_VCPU_PSCI_0_2 1 /* CPU uses PSCI v0.2 */ | ||
590 | |||
591 | @@ -166,6 +173,12 @@ struct kvm_arch_memory_slot { | ||
592 | #define KVM_REG_ARM_VFP_FPINST 0x1009 | ||
593 | #define KVM_REG_ARM_VFP_FPINST2 0x100A | ||
594 | |||
595 | +/* KVM-as-firmware specific pseudo-registers */ | ||
596 | +#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) | ||
597 | +#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM | KVM_REG_SIZE_U64 | \ | ||
598 | + KVM_REG_ARM_FW | ((r) & 0xffff)) | ||
599 | +#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) | ||
600 | + | ||
601 | /* Device Control API: ARM VGIC */ | ||
602 | #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 | ||
603 | #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 | ||
604 | diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h | ||
605 | index 3051f86a9b5f..702de7a2b024 100644 | ||
606 | --- a/tools/arch/arm64/include/uapi/asm/kvm.h | ||
607 | +++ b/tools/arch/arm64/include/uapi/asm/kvm.h | ||
608 | @@ -195,6 +195,12 @@ struct kvm_arch_memory_slot { | ||
609 | #define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2) | ||
610 | #define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2) | ||
611 | |||
612 | +/* KVM-as-firmware specific pseudo-registers */ | ||
613 | +#define KVM_REG_ARM_FW (0x0014 << KVM_REG_ARM_COPROC_SHIFT) | ||
614 | +#define KVM_REG_ARM_FW_REG(r) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ | ||
615 | + KVM_REG_ARM_FW | ((r) & 0xffff)) | ||
616 | +#define KVM_REG_ARM_PSCI_VERSION KVM_REG_ARM_FW_REG(0) | ||
617 | + | ||
618 | /* Device Control API: ARM VGIC */ | ||
619 | #define KVM_DEV_ARM_VGIC_GRP_ADDR 0 | ||
620 | #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1 | ||
621 | diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h | ||
622 | index c93cf35ce379..0fb1326c3ea2 100644 | ||
623 | --- a/tools/arch/powerpc/include/uapi/asm/kvm.h | ||
624 | +++ b/tools/arch/powerpc/include/uapi/asm/kvm.h | ||
625 | @@ -596,6 +596,7 @@ struct kvm_get_htab_header { | ||
626 | #define KVM_REG_PPC_TM_VSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U32 | 0x67) | ||
627 | #define KVM_REG_PPC_TM_DSCR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x68) | ||
628 | #define KVM_REG_PPC_TM_TAR (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x69) | ||
629 | +#define KVM_REG_PPC_TM_XER (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x6a) | ||
630 | |||
631 | /* PPC64 eXternal Interrupt Controller Specification */ | ||
632 | #define KVM_DEV_XICS_GRP_SOURCES 1 /* 64-bit source attributes */ | ||
633 | diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h | ||
634 | index a2ffec4139ad..81c02e198527 100644 | ||
635 | --- a/tools/arch/s390/include/uapi/asm/kvm.h | ||
636 | +++ b/tools/arch/s390/include/uapi/asm/kvm.h | ||
637 | @@ -197,6 +197,7 @@ struct kvm_guest_debug_arch { | ||
638 | #define KVM_SYNC_VRS (1UL << 6) | ||
639 | #define KVM_SYNC_RICCB (1UL << 7) | ||
640 | #define KVM_SYNC_FPRS (1UL << 8) | ||
641 | +#define KVM_SYNC_BPBC (1UL << 10) | ||
642 | /* definition of registers in kvm_run */ | ||
643 | struct kvm_sync_regs { | ||
644 | __u64 prefix; /* prefix register */ | ||
645 | @@ -217,7 +218,9 @@ struct kvm_sync_regs { | ||
646 | }; | ||
647 | __u8 reserved[512]; /* for future vector expansion */ | ||
648 | __u32 fpc; /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */ | ||
649 | - __u8 padding[52]; /* riccb needs to be 64byte aligned */ | ||
650 | + __u8 bpbc : 1; /* bp mode */ | ||
651 | + __u8 reserved2 : 7; | ||
652 | + __u8 padding1[51]; /* riccb needs to be 64byte aligned */ | ||
653 | __u8 riccb[64]; /* runtime instrumentation controls block */ | ||
654 | }; | ||
655 | |||
656 | diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h | ||
657 | index f79669a38c0c..c278f276c9b3 100644 | ||
658 | --- a/tools/arch/x86/include/asm/cpufeatures.h | ||
659 | +++ b/tools/arch/x86/include/asm/cpufeatures.h | ||
660 | @@ -12,7 +12,7 @@ | ||
661 | /* | ||
662 | * Defines x86 CPU feature bits | ||
663 | */ | ||
664 | -#define NCAPINTS 18 /* N 32-bit words worth of info */ | ||
665 | +#define NCAPINTS 19 /* N 32-bit words worth of info */ | ||
666 | #define NBUGINTS 1 /* N 32-bit bug flags */ | ||
667 | |||
668 | /* | ||
669 | @@ -189,17 +189,32 @@ | ||
670 | |||
671 | #define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */ | ||
672 | #define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */ | ||
673 | +#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 4) /* Effectively INVPCID && CR4.PCIDE=1 */ | ||
674 | |||
675 | #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ | ||
676 | #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ | ||
677 | |||
678 | -#define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */ | ||
679 | -#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */ | ||
680 | -#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */ | ||
681 | +#define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */ | ||
682 | +#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */ | ||
683 | + | ||
684 | +#define X86_FEATURE_MSR_SPEC_CTRL ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */ | ||
685 | +#define X86_FEATURE_SSBD ( 7*32+17) /* Speculative Store Bypass Disable */ | ||
686 | + | ||
687 | +#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */ | ||
688 | |||
689 | /* Because the ALTERNATIVE scheme is for members of the X86_FEATURE club... */ | ||
690 | #define X86_FEATURE_KAISER ( 7*32+31) /* CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */ | ||
691 | |||
692 | +#define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ | ||
693 | +#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ | ||
694 | +#define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */ | ||
695 | +#define X86_FEATURE_LS_CFG_SSBD ( 7*32+24) /* "" AMD SSBD implementation */ | ||
696 | +#define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */ | ||
697 | +#define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ | ||
698 | +#define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ | ||
699 | +#define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */ | ||
700 | + | ||
701 | + | ||
702 | /* Virtualization flags: Linux defined, word 8 */ | ||
703 | #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ | ||
704 | #define X86_FEATURE_VNMI ( 8*32+ 1) /* Intel Virtual NMI */ | ||
705 | @@ -231,6 +246,7 @@ | ||
706 | #define X86_FEATURE_SMAP ( 9*32+20) /* Supervisor Mode Access Prevention */ | ||
707 | #define X86_FEATURE_CLFLUSHOPT ( 9*32+23) /* CLFLUSHOPT instruction */ | ||
708 | #define X86_FEATURE_CLWB ( 9*32+24) /* CLWB instruction */ | ||
709 | +#define X86_FEATURE_INTEL_PT ( 9*32+25) /* Intel Processor Trace */ | ||
710 | #define X86_FEATURE_AVX512PF ( 9*32+26) /* AVX-512 Prefetch */ | ||
711 | #define X86_FEATURE_AVX512ER ( 9*32+27) /* AVX-512 Exponential and Reciprocal */ | ||
712 | #define X86_FEATURE_AVX512CD ( 9*32+28) /* AVX-512 Conflict Detection */ | ||
713 | @@ -255,6 +271,10 @@ | ||
714 | /* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */ | ||
715 | #define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */ | ||
716 | #define X86_FEATURE_IRPERF (13*32+1) /* Instructions Retired Count */ | ||
717 | +#define X86_FEATURE_AMD_IBPB (13*32+12) /* Indirect Branch Prediction Barrier */ | ||
718 | +#define X86_FEATURE_AMD_IBRS (13*32+14) /* Indirect Branch Restricted Speculation */ | ||
719 | +#define X86_FEATURE_AMD_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */ | ||
720 | +#define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */ | ||
721 | |||
722 | /* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */ | ||
723 | #define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ | ||
724 | @@ -290,6 +310,16 @@ | ||
725 | #define X86_FEATURE_SUCCOR (17*32+1) /* Uncorrectable error containment and recovery */ | ||
726 | #define X86_FEATURE_SMCA (17*32+3) /* Scalable MCA */ | ||
727 | |||
728 | + | ||
729 | +/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ | ||
730 | +#define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ | ||
731 | +#define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ | ||
732 | +#define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ | ||
733 | +#define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ | ||
734 | +#define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ | ||
735 | +#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ | ||
736 | +#define X86_FEATURE_SPEC_CTRL_SSBD (18*32+31) /* "" Speculative Store Bypass Disable */ | ||
737 | + | ||
738 | /* | ||
739 | * BUG word(s) | ||
740 | */ | ||
741 | @@ -314,4 +344,10 @@ | ||
742 | #define X86_BUG_NULL_SEG X86_BUG(10) /* Nulling a selector preserves the base */ | ||
743 | #define X86_BUG_SWAPGS_FENCE X86_BUG(11) /* SWAPGS without input dep on GS */ | ||
744 | #define X86_BUG_MONITOR X86_BUG(12) /* IPI required to wake up remote CPU */ | ||
745 | +#define X86_BUG_AMD_E400 X86_BUG(13) /* CPU is among the affected by Erratum 400 */ | ||
746 | +#define X86_BUG_CPU_MELTDOWN X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */ | ||
747 | +#define X86_BUG_SPECTRE_V1 X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */ | ||
748 | +#define X86_BUG_SPECTRE_V2 X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */ | ||
749 | +#define X86_BUG_SPEC_STORE_BYPASS X86_BUG(17) /* CPU is affected by speculative store bypass attack */ | ||
750 | + | ||
751 | #endif /* _ASM_X86_CPUFEATURES_H */ | ||
752 | diff --git a/tools/arch/x86/include/asm/disabled-features.h b/tools/arch/x86/include/asm/disabled-features.h | ||
753 | index 85599ad4d024..1f8cca459c6c 100644 | ||
754 | --- a/tools/arch/x86/include/asm/disabled-features.h | ||
755 | +++ b/tools/arch/x86/include/asm/disabled-features.h | ||
756 | @@ -21,11 +21,13 @@ | ||
757 | # define DISABLE_K6_MTRR (1<<(X86_FEATURE_K6_MTRR & 31)) | ||
758 | # define DISABLE_CYRIX_ARR (1<<(X86_FEATURE_CYRIX_ARR & 31)) | ||
759 | # define DISABLE_CENTAUR_MCR (1<<(X86_FEATURE_CENTAUR_MCR & 31)) | ||
760 | +# define DISABLE_PCID 0 | ||
761 | #else | ||
762 | # define DISABLE_VME 0 | ||
763 | # define DISABLE_K6_MTRR 0 | ||
764 | # define DISABLE_CYRIX_ARR 0 | ||
765 | # define DISABLE_CENTAUR_MCR 0 | ||
766 | +# define DISABLE_PCID (1<<(X86_FEATURE_PCID & 31)) | ||
767 | #endif /* CONFIG_X86_64 */ | ||
768 | |||
769 | #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS | ||
770 | @@ -43,7 +45,7 @@ | ||
771 | #define DISABLED_MASK1 0 | ||
772 | #define DISABLED_MASK2 0 | ||
773 | #define DISABLED_MASK3 (DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR) | ||
774 | -#define DISABLED_MASK4 0 | ||
775 | +#define DISABLED_MASK4 (DISABLE_PCID) | ||
776 | #define DISABLED_MASK5 0 | ||
777 | #define DISABLED_MASK6 0 | ||
778 | #define DISABLED_MASK7 0 | ||
779 | @@ -57,6 +59,7 @@ | ||
780 | #define DISABLED_MASK15 0 | ||
781 | #define DISABLED_MASK16 (DISABLE_PKU|DISABLE_OSPKE) | ||
782 | #define DISABLED_MASK17 0 | ||
783 | -#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) | ||
784 | +#define DISABLED_MASK18 0 | ||
785 | +#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) | ||
786 | |||
787 | #endif /* _ASM_X86_DISABLED_FEATURES_H */ | ||
788 | diff --git a/tools/arch/x86/include/asm/required-features.h b/tools/arch/x86/include/asm/required-features.h | ||
789 | index fac9a5c0abe9..6847d85400a8 100644 | ||
790 | --- a/tools/arch/x86/include/asm/required-features.h | ||
791 | +++ b/tools/arch/x86/include/asm/required-features.h | ||
792 | @@ -100,6 +100,7 @@ | ||
793 | #define REQUIRED_MASK15 0 | ||
794 | #define REQUIRED_MASK16 0 | ||
795 | #define REQUIRED_MASK17 0 | ||
796 | -#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18) | ||
797 | +#define REQUIRED_MASK18 0 | ||
798 | +#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19) | ||
799 | |||
800 | #endif /* _ASM_X86_REQUIRED_FEATURES_H */ | ||
801 | diff --git a/tools/include/asm-generic/bitops.h b/tools/include/asm-generic/bitops.h | ||
802 | index 653d1bad77de..0304600121da 100644 | ||
803 | --- a/tools/include/asm-generic/bitops.h | ||
804 | +++ b/tools/include/asm-generic/bitops.h | ||
805 | @@ -13,6 +13,7 @@ | ||
806 | */ | ||
807 | |||
808 | #include <asm-generic/bitops/__ffs.h> | ||
809 | +#include <asm-generic/bitops/__ffz.h> | ||
810 | #include <asm-generic/bitops/fls.h> | ||
811 | #include <asm-generic/bitops/__fls.h> | ||
812 | #include <asm-generic/bitops/fls64.h> | ||
813 | diff --git a/tools/include/asm-generic/bitops/__ffz.h b/tools/include/asm-generic/bitops/__ffz.h | ||
814 | new file mode 100644 | ||
815 | index 000000000000..6744bd4cdf46 | ||
816 | --- /dev/null | ||
817 | +++ b/tools/include/asm-generic/bitops/__ffz.h | ||
818 | @@ -0,0 +1,12 @@ | ||
819 | +#ifndef _ASM_GENERIC_BITOPS_FFZ_H_ | ||
820 | +#define _ASM_GENERIC_BITOPS_FFZ_H_ | ||
821 | + | ||
822 | +/* | ||
823 | + * ffz - find first zero in word. | ||
824 | + * @word: The word to search | ||
825 | + * | ||
826 | + * Undefined if no zero exists, so code should check against ~0UL first. | ||
827 | + */ | ||
828 | +#define ffz(x) __ffs(~(x)) | ||
829 | + | ||
830 | +#endif /* _ASM_GENERIC_BITOPS_FFZ_H_ */ | ||
831 | diff --git a/tools/include/asm-generic/bitops/find.h b/tools/include/asm-generic/bitops/find.h | ||
832 | index 31f51547fcd4..5538ecdc964a 100644 | ||
833 | --- a/tools/include/asm-generic/bitops/find.h | ||
834 | +++ b/tools/include/asm-generic/bitops/find.h | ||
835 | @@ -15,6 +15,21 @@ extern unsigned long find_next_bit(const unsigned long *addr, unsigned long | ||
836 | size, unsigned long offset); | ||
837 | #endif | ||
838 | |||
839 | +#ifndef find_next_zero_bit | ||
840 | + | ||
841 | +/** | ||
842 | + * find_next_zero_bit - find the next cleared bit in a memory region | ||
843 | + * @addr: The address to base the search on | ||
844 | + * @offset: The bitnumber to start searching at | ||
845 | + * @size: The bitmap size in bits | ||
846 | + * | ||
847 | + * Returns the bit number of the next zero bit | ||
848 | + * If no bits are zero, returns @size. | ||
849 | + */ | ||
850 | +unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, | ||
851 | + unsigned long offset); | ||
852 | +#endif | ||
853 | + | ||
854 | #ifndef find_first_bit | ||
855 | |||
856 | /** | ||
857 | @@ -30,4 +45,17 @@ extern unsigned long find_first_bit(const unsigned long *addr, | ||
858 | |||
859 | #endif /* find_first_bit */ | ||
860 | |||
861 | +#ifndef find_first_zero_bit | ||
862 | + | ||
863 | +/** | ||
864 | + * find_first_zero_bit - find the first cleared bit in a memory region | ||
865 | + * @addr: The address to start the search at | ||
866 | + * @size: The maximum number of bits to search | ||
867 | + * | ||
868 | + * Returns the bit number of the first cleared bit. | ||
869 | + * If no bits are zero, returns @size. | ||
870 | + */ | ||
871 | +unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size); | ||
872 | +#endif | ||
873 | + | ||
874 | #endif /*_TOOLS_LINUX_ASM_GENERIC_BITOPS_FIND_H_ */ | ||
875 | diff --git a/tools/include/linux/atomic.h b/tools/include/linux/atomic.h | ||
876 | index 4e3d3d18ebab..9f21fc2b092b 100644 | ||
877 | --- a/tools/include/linux/atomic.h | ||
878 | +++ b/tools/include/linux/atomic.h | ||
879 | @@ -3,4 +3,10 @@ | ||
880 | |||
881 | #include <asm/atomic.h> | ||
882 | |||
883 | +/* atomic_cmpxchg_relaxed */ | ||
884 | +#ifndef atomic_cmpxchg_relaxed | ||
885 | +#define atomic_cmpxchg_relaxed atomic_cmpxchg | ||
886 | +#define atomic_cmpxchg_release atomic_cmpxchg | ||
887 | +#endif /* atomic_cmpxchg_relaxed */ | ||
888 | + | ||
889 | #endif /* __TOOLS_LINUX_ATOMIC_H */ | ||
890 | diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h | ||
891 | index 43c1c5021e4b..eef41d500e9e 100644 | ||
892 | --- a/tools/include/linux/bitmap.h | ||
893 | +++ b/tools/include/linux/bitmap.h | ||
894 | @@ -35,6 +35,32 @@ static inline void bitmap_zero(unsigned long *dst, int nbits) | ||
895 | } | ||
896 | } | ||
897 | |||
898 | +static inline void bitmap_fill(unsigned long *dst, unsigned int nbits) | ||
899 | +{ | ||
900 | + unsigned int nlongs = BITS_TO_LONGS(nbits); | ||
901 | + if (!small_const_nbits(nbits)) { | ||
902 | + unsigned int len = (nlongs - 1) * sizeof(unsigned long); | ||
903 | + memset(dst, 0xff, len); | ||
904 | + } | ||
905 | + dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); | ||
906 | +} | ||
907 | + | ||
908 | +static inline int bitmap_empty(const unsigned long *src, unsigned nbits) | ||
909 | +{ | ||
910 | + if (small_const_nbits(nbits)) | ||
911 | + return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); | ||
912 | + | ||
913 | + return find_first_bit(src, nbits) == nbits; | ||
914 | +} | ||
915 | + | ||
916 | +static inline int bitmap_full(const unsigned long *src, unsigned int nbits) | ||
917 | +{ | ||
918 | + if (small_const_nbits(nbits)) | ||
919 | + return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); | ||
920 | + | ||
921 | + return find_first_zero_bit(src, nbits) == nbits; | ||
922 | +} | ||
923 | + | ||
924 | static inline int bitmap_weight(const unsigned long *src, int nbits) | ||
925 | { | ||
926 | if (small_const_nbits(nbits)) | ||
927 | diff --git a/tools/include/linux/bitops.h b/tools/include/linux/bitops.h | ||
928 | index 49c929a104ee..fc446343ff41 100644 | ||
929 | --- a/tools/include/linux/bitops.h | ||
930 | +++ b/tools/include/linux/bitops.h | ||
931 | @@ -39,6 +39,11 @@ extern unsigned long __sw_hweight64(__u64 w); | ||
932 | (bit) < (size); \ | ||
933 | (bit) = find_next_bit((addr), (size), (bit) + 1)) | ||
934 | |||
935 | +#define for_each_clear_bit(bit, addr, size) \ | ||
936 | + for ((bit) = find_first_zero_bit((addr), (size)); \ | ||
937 | + (bit) < (size); \ | ||
938 | + (bit) = find_next_zero_bit((addr), (size), (bit) + 1)) | ||
939 | + | ||
940 | /* same as for_each_set_bit() but use bit as value to start with */ | ||
941 | #define for_each_set_bit_from(bit, addr, size) \ | ||
942 | for ((bit) = find_next_bit((addr), (size), (bit)); \ | ||
943 | diff --git a/tools/include/linux/bug.h b/tools/include/linux/bug.h | ||
944 | new file mode 100644 | ||
945 | index 000000000000..8e4a4f49135d | ||
946 | --- /dev/null | ||
947 | +++ b/tools/include/linux/bug.h | ||
948 | @@ -0,0 +1,10 @@ | ||
949 | +#ifndef _TOOLS_PERF_LINUX_BUG_H | ||
950 | +#define _TOOLS_PERF_LINUX_BUG_H | ||
951 | + | ||
952 | +/* Force a compilation error if condition is true, but also produce a | ||
953 | + result (of value 0 and type size_t), so the expression can be used | ||
954 | + e.g. in a structure initializer (or where-ever else comma expressions | ||
955 | + aren't permitted). */ | ||
956 | +#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) | ||
957 | + | ||
958 | +#endif /* _TOOLS_PERF_LINUX_BUG_H */ | ||
959 | diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h | ||
960 | new file mode 100644 | ||
961 | index 000000000000..825d44f89a29 | ||
962 | --- /dev/null | ||
963 | +++ b/tools/include/linux/compiler-gcc.h | ||
964 | @@ -0,0 +1,21 @@ | ||
965 | +#ifndef _TOOLS_LINUX_COMPILER_H_ | ||
966 | +#error "Please don't include <linux/compiler-gcc.h> directly, include <linux/compiler.h> instead." | ||
967 | +#endif | ||
968 | + | ||
969 | +/* | ||
970 | + * Common definitions for all gcc versions go here. | ||
971 | + */ | ||
972 | +#define GCC_VERSION (__GNUC__ * 10000 \ | ||
973 | + + __GNUC_MINOR__ * 100 \ | ||
974 | + + __GNUC_PATCHLEVEL__) | ||
975 | + | ||
976 | +#if GCC_VERSION >= 70000 && !defined(__CHECKER__) | ||
977 | +# define __fallthrough __attribute__ ((fallthrough)) | ||
978 | +#endif | ||
979 | + | ||
980 | +#if GCC_VERSION >= 40300 | ||
981 | +# define __compiletime_error(message) __attribute__((error(message))) | ||
982 | +#endif /* GCC_VERSION >= 40300 */ | ||
983 | + | ||
984 | +/* &a[0] degrades to a pointer: a different type from an array */ | ||
985 | +#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) | ||
986 | diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h | ||
987 | index d94179f94caa..23299d7e7160 100644 | ||
988 | --- a/tools/include/linux/compiler.h | ||
989 | +++ b/tools/include/linux/compiler.h | ||
990 | @@ -1,6 +1,14 @@ | ||
991 | #ifndef _TOOLS_LINUX_COMPILER_H_ | ||
992 | #define _TOOLS_LINUX_COMPILER_H_ | ||
993 | |||
994 | +#ifdef __GNUC__ | ||
995 | +#include <linux/compiler-gcc.h> | ||
996 | +#endif | ||
997 | + | ||
998 | +#ifndef __compiletime_error | ||
999 | +# define __compiletime_error(message) | ||
1000 | +#endif | ||
1001 | + | ||
1002 | /* Optimization barrier */ | ||
1003 | /* The "volatile" is due to gcc bugs */ | ||
1004 | #define barrier() __asm__ __volatile__("": : :"memory") | ||
1005 | @@ -9,6 +17,11 @@ | ||
1006 | # define __always_inline inline __attribute__((always_inline)) | ||
1007 | #endif | ||
1008 | |||
1009 | +/* Are two types/vars the same type (ignoring qualifiers)? */ | ||
1010 | +#ifndef __same_type | ||
1011 | +# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) | ||
1012 | +#endif | ||
1013 | + | ||
1014 | #ifdef __ANDROID__ | ||
1015 | /* | ||
1016 | * FIXME: Big hammer to get rid of tons of: | ||
1017 | @@ -21,6 +34,8 @@ | ||
1018 | #endif | ||
1019 | |||
1020 | #define __user | ||
1021 | +#define __rcu | ||
1022 | +#define __read_mostly | ||
1023 | |||
1024 | #ifndef __attribute_const__ | ||
1025 | # define __attribute_const__ | ||
1026 | @@ -50,6 +65,8 @@ | ||
1027 | # define unlikely(x) __builtin_expect(!!(x), 0) | ||
1028 | #endif | ||
1029 | |||
1030 | +#define uninitialized_var(x) x = *(&(x)) | ||
1031 | + | ||
1032 | #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) | ||
1033 | |||
1034 | #include <linux/types.h> | ||
1035 | @@ -128,11 +145,7 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s | ||
1036 | |||
1037 | |||
1038 | #ifndef __fallthrough | ||
1039 | -# if defined(__GNUC__) && __GNUC__ >= 7 | ||
1040 | -# define __fallthrough __attribute__ ((fallthrough)) | ||
1041 | -# else | ||
1042 | -# define __fallthrough | ||
1043 | -# endif | ||
1044 | +# define __fallthrough | ||
1045 | #endif | ||
1046 | |||
1047 | #endif /* _TOOLS_LINUX_COMPILER_H */ | ||
1048 | diff --git a/tools/include/linux/hashtable.h b/tools/include/linux/hashtable.h | ||
1049 | index c65cc0aa2659..251eabf2a05e 100644 | ||
1050 | --- a/tools/include/linux/hashtable.h | ||
1051 | +++ b/tools/include/linux/hashtable.h | ||
1052 | @@ -13,10 +13,6 @@ | ||
1053 | #include <linux/hash.h> | ||
1054 | #include <linux/log2.h> | ||
1055 | |||
1056 | -#ifndef ARRAY_SIZE | ||
1057 | -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
1058 | -#endif | ||
1059 | - | ||
1060 | #define DEFINE_HASHTABLE(name, bits) \ | ||
1061 | struct hlist_head name[1 << (bits)] = \ | ||
1062 | { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } | ||
1063 | diff --git a/tools/include/linux/kernel.h b/tools/include/linux/kernel.h | ||
1064 | index 28607db02bd3..73ccc48126bb 100644 | ||
1065 | --- a/tools/include/linux/kernel.h | ||
1066 | +++ b/tools/include/linux/kernel.h | ||
1067 | @@ -4,6 +4,11 @@ | ||
1068 | #include <stdarg.h> | ||
1069 | #include <stddef.h> | ||
1070 | #include <assert.h> | ||
1071 | +#include <linux/compiler.h> | ||
1072 | + | ||
1073 | +#ifndef UINT_MAX | ||
1074 | +#define UINT_MAX (~0U) | ||
1075 | +#endif | ||
1076 | |||
1077 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) | ||
1078 | |||
1079 | @@ -72,6 +77,8 @@ | ||
1080 | int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); | ||
1081 | int scnprintf(char * buf, size_t size, const char * fmt, ...); | ||
1082 | |||
1083 | +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) | ||
1084 | + | ||
1085 | /* | ||
1086 | * This looks more complex than it should be. But we need to | ||
1087 | * get the type for the ~ right in round_down (it needs to be | ||
1088 | diff --git a/tools/include/linux/log2.h b/tools/include/linux/log2.h | ||
1089 | index d5677d39c1e4..0325cefc2220 100644 | ||
1090 | --- a/tools/include/linux/log2.h | ||
1091 | +++ b/tools/include/linux/log2.h | ||
1092 | @@ -12,6 +12,9 @@ | ||
1093 | #ifndef _TOOLS_LINUX_LOG2_H | ||
1094 | #define _TOOLS_LINUX_LOG2_H | ||
1095 | |||
1096 | +#include <linux/bitops.h> | ||
1097 | +#include <linux/types.h> | ||
1098 | + | ||
1099 | /* | ||
1100 | * non-constant log of base 2 calculators | ||
1101 | * - the arch may override these in asm/bitops.h if they can be implemented | ||
1102 | diff --git a/tools/include/linux/refcount.h b/tools/include/linux/refcount.h | ||
1103 | new file mode 100644 | ||
1104 | index 000000000000..a0177c1f55b1 | ||
1105 | --- /dev/null | ||
1106 | +++ b/tools/include/linux/refcount.h | ||
1107 | @@ -0,0 +1,151 @@ | ||
1108 | +#ifndef _TOOLS_LINUX_REFCOUNT_H | ||
1109 | +#define _TOOLS_LINUX_REFCOUNT_H | ||
1110 | + | ||
1111 | +/* | ||
1112 | + * Variant of atomic_t specialized for reference counts. | ||
1113 | + * | ||
1114 | + * The interface matches the atomic_t interface (to aid in porting) but only | ||
1115 | + * provides the few functions one should use for reference counting. | ||
1116 | + * | ||
1117 | + * It differs in that the counter saturates at UINT_MAX and will not move once | ||
1118 | + * there. This avoids wrapping the counter and causing 'spurious' | ||
1119 | + * use-after-free issues. | ||
1120 | + * | ||
1121 | + * Memory ordering rules are slightly relaxed wrt regular atomic_t functions | ||
1122 | + * and provide only what is strictly required for refcounts. | ||
1123 | + * | ||
1124 | + * The increments are fully relaxed; these will not provide ordering. The | ||
1125 | + * rationale is that whatever is used to obtain the object we're increasing the | ||
1126 | + * reference count on will provide the ordering. For locked data structures, | ||
1127 | + * its the lock acquire, for RCU/lockless data structures its the dependent | ||
1128 | + * load. | ||
1129 | + * | ||
1130 | + * Do note that inc_not_zero() provides a control dependency which will order | ||
1131 | + * future stores against the inc, this ensures we'll never modify the object | ||
1132 | + * if we did not in fact acquire a reference. | ||
1133 | + * | ||
1134 | + * The decrements will provide release order, such that all the prior loads and | ||
1135 | + * stores will be issued before, it also provides a control dependency, which | ||
1136 | + * will order us against the subsequent free(). | ||
1137 | + * | ||
1138 | + * The control dependency is against the load of the cmpxchg (ll/sc) that | ||
1139 | + * succeeded. This means the stores aren't fully ordered, but this is fine | ||
1140 | + * because the 1->0 transition indicates no concurrency. | ||
1141 | + * | ||
1142 | + * Note that the allocator is responsible for ordering things between free() | ||
1143 | + * and alloc(). | ||
1144 | + * | ||
1145 | + */ | ||
1146 | + | ||
1147 | +#include <linux/atomic.h> | ||
1148 | +#include <linux/kernel.h> | ||
1149 | + | ||
1150 | +#ifdef NDEBUG | ||
1151 | +#define REFCOUNT_WARN(cond, str) (void)(cond) | ||
1152 | +#define __refcount_check | ||
1153 | +#else | ||
1154 | +#define REFCOUNT_WARN(cond, str) BUG_ON(cond) | ||
1155 | +#define __refcount_check __must_check | ||
1156 | +#endif | ||
1157 | + | ||
1158 | +typedef struct refcount_struct { | ||
1159 | + atomic_t refs; | ||
1160 | +} refcount_t; | ||
1161 | + | ||
1162 | +#define REFCOUNT_INIT(n) { .refs = ATOMIC_INIT(n), } | ||
1163 | + | ||
1164 | +static inline void refcount_set(refcount_t *r, unsigned int n) | ||
1165 | +{ | ||
1166 | + atomic_set(&r->refs, n); | ||
1167 | +} | ||
1168 | + | ||
1169 | +static inline unsigned int refcount_read(const refcount_t *r) | ||
1170 | +{ | ||
1171 | + return atomic_read(&r->refs); | ||
1172 | +} | ||
1173 | + | ||
1174 | +/* | ||
1175 | + * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN. | ||
1176 | + * | ||
1177 | + * Provides no memory ordering, it is assumed the caller has guaranteed the | ||
1178 | + * object memory to be stable (RCU, etc.). It does provide a control dependency | ||
1179 | + * and thereby orders future stores. See the comment on top. | ||
1180 | + */ | ||
1181 | +static inline __refcount_check | ||
1182 | +bool refcount_inc_not_zero(refcount_t *r) | ||
1183 | +{ | ||
1184 | + unsigned int old, new, val = atomic_read(&r->refs); | ||
1185 | + | ||
1186 | + for (;;) { | ||
1187 | + new = val + 1; | ||
1188 | + | ||
1189 | + if (!val) | ||
1190 | + return false; | ||
1191 | + | ||
1192 | + if (unlikely(!new)) | ||
1193 | + return true; | ||
1194 | + | ||
1195 | + old = atomic_cmpxchg_relaxed(&r->refs, val, new); | ||
1196 | + if (old == val) | ||
1197 | + break; | ||
1198 | + | ||
1199 | + val = old; | ||
1200 | + } | ||
1201 | + | ||
1202 | + REFCOUNT_WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n"); | ||
1203 | + | ||
1204 | + return true; | ||
1205 | +} | ||
1206 | + | ||
1207 | +/* | ||
1208 | + * Similar to atomic_inc(), will saturate at UINT_MAX and WARN. | ||
1209 | + * | ||
1210 | + * Provides no memory ordering, it is assumed the caller already has a | ||
1211 | + * reference on the object, will WARN when this is not so. | ||
1212 | + */ | ||
1213 | +static inline void refcount_inc(refcount_t *r) | ||
1214 | +{ | ||
1215 | + REFCOUNT_WARN(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n"); | ||
1216 | +} | ||
1217 | + | ||
1218 | +/* | ||
1219 | + * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to | ||
1220 | + * decrement when saturated at UINT_MAX. | ||
1221 | + * | ||
1222 | + * Provides release memory ordering, such that prior loads and stores are done | ||
1223 | + * before, and provides a control dependency such that free() must come after. | ||
1224 | + * See the comment on top. | ||
1225 | + */ | ||
1226 | +static inline __refcount_check | ||
1227 | +bool refcount_sub_and_test(unsigned int i, refcount_t *r) | ||
1228 | +{ | ||
1229 | + unsigned int old, new, val = atomic_read(&r->refs); | ||
1230 | + | ||
1231 | + for (;;) { | ||
1232 | + if (unlikely(val == UINT_MAX)) | ||
1233 | + return false; | ||
1234 | + | ||
1235 | + new = val - i; | ||
1236 | + if (new > val) { | ||
1237 | + REFCOUNT_WARN(new > val, "refcount_t: underflow; use-after-free.\n"); | ||
1238 | + return false; | ||
1239 | + } | ||
1240 | + | ||
1241 | + old = atomic_cmpxchg_release(&r->refs, val, new); | ||
1242 | + if (old == val) | ||
1243 | + break; | ||
1244 | + | ||
1245 | + val = old; | ||
1246 | + } | ||
1247 | + | ||
1248 | + return !new; | ||
1249 | +} | ||
1250 | + | ||
1251 | +static inline __refcount_check | ||
1252 | +bool refcount_dec_and_test(refcount_t *r) | ||
1253 | +{ | ||
1254 | + return refcount_sub_and_test(1, r); | ||
1255 | +} | ||
1256 | + | ||
1257 | + | ||
1258 | +#endif /* _ATOMIC_LINUX_REFCOUNT_H */ | ||
1259 | diff --git a/tools/include/linux/spinlock.h b/tools/include/linux/spinlock.h | ||
1260 | new file mode 100644 | ||
1261 | index 000000000000..58397dcb19d6 | ||
1262 | --- /dev/null | ||
1263 | +++ b/tools/include/linux/spinlock.h | ||
1264 | @@ -0,0 +1,5 @@ | ||
1265 | +#define spinlock_t pthread_mutex_t | ||
1266 | +#define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; | ||
1267 | + | ||
1268 | +#define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) | ||
1269 | +#define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) | ||
1270 | diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h | ||
1271 | index 8ebf6278b2ef..77a28a26a670 100644 | ||
1272 | --- a/tools/include/linux/types.h | ||
1273 | +++ b/tools/include/linux/types.h | ||
1274 | @@ -7,6 +7,7 @@ | ||
1275 | |||
1276 | #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ | ||
1277 | #include <asm/types.h> | ||
1278 | +#include <asm/posix_types.h> | ||
1279 | |||
1280 | struct page; | ||
1281 | struct kmem_cache; | ||
1282 | @@ -42,11 +43,7 @@ typedef __s8 s8; | ||
1283 | #else | ||
1284 | #define __bitwise__ | ||
1285 | #endif | ||
1286 | -#ifdef __CHECK_ENDIAN__ | ||
1287 | #define __bitwise __bitwise__ | ||
1288 | -#else | ||
1289 | -#define __bitwise | ||
1290 | -#endif | ||
1291 | |||
1292 | #define __force | ||
1293 | #define __user | ||
1294 | diff --git a/tools/include/uapi/asm-generic/mman-common.h b/tools/include/uapi/asm-generic/mman-common.h | ||
1295 | index 58274382a616..8c27db0c5c08 100644 | ||
1296 | --- a/tools/include/uapi/asm-generic/mman-common.h | ||
1297 | +++ b/tools/include/uapi/asm-generic/mman-common.h | ||
1298 | @@ -72,4 +72,9 @@ | ||
1299 | #define MAP_HUGE_SHIFT 26 | ||
1300 | #define MAP_HUGE_MASK 0x3f | ||
1301 | |||
1302 | +#define PKEY_DISABLE_ACCESS 0x1 | ||
1303 | +#define PKEY_DISABLE_WRITE 0x2 | ||
1304 | +#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\ | ||
1305 | + PKEY_DISABLE_WRITE) | ||
1306 | + | ||
1307 | #endif /* __ASM_GENERIC_MMAN_COMMON_H */ | ||
1308 | diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h | ||
1309 | index 9e5fc168c8a3..f09c70b97eca 100644 | ||
1310 | --- a/tools/include/uapi/linux/bpf.h | ||
1311 | +++ b/tools/include/uapi/linux/bpf.h | ||
1312 | @@ -95,6 +95,7 @@ enum bpf_prog_type { | ||
1313 | BPF_PROG_TYPE_SCHED_ACT, | ||
1314 | BPF_PROG_TYPE_TRACEPOINT, | ||
1315 | BPF_PROG_TYPE_XDP, | ||
1316 | + BPF_PROG_TYPE_PERF_EVENT, | ||
1317 | }; | ||
1318 | |||
1319 | #define BPF_PSEUDO_MAP_FD 1 | ||
1320 | @@ -375,6 +376,56 @@ enum bpf_func_id { | ||
1321 | */ | ||
1322 | BPF_FUNC_probe_write_user, | ||
1323 | |||
1324 | + /** | ||
1325 | + * bpf_current_task_under_cgroup(map, index) - Check cgroup2 membership of current task | ||
1326 | + * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type | ||
1327 | + * @index: index of the cgroup in the bpf_map | ||
1328 | + * Return: | ||
1329 | + * == 0 current failed the cgroup2 descendant test | ||
1330 | + * == 1 current succeeded the cgroup2 descendant test | ||
1331 | + * < 0 error | ||
1332 | + */ | ||
1333 | + BPF_FUNC_current_task_under_cgroup, | ||
1334 | + | ||
1335 | + /** | ||
1336 | + * bpf_skb_change_tail(skb, len, flags) | ||
1337 | + * The helper will resize the skb to the given new size, | ||
1338 | + * to be used f.e. with control messages. | ||
1339 | + * @skb: pointer to skb | ||
1340 | + * @len: new skb length | ||
1341 | + * @flags: reserved | ||
1342 | + * Return: 0 on success or negative error | ||
1343 | + */ | ||
1344 | + BPF_FUNC_skb_change_tail, | ||
1345 | + | ||
1346 | + /** | ||
1347 | + * bpf_skb_pull_data(skb, len) | ||
1348 | + * The helper will pull in non-linear data in case the | ||
1349 | + * skb is non-linear and not all of len are part of the | ||
1350 | + * linear section. Only needed for read/write with direct | ||
1351 | + * packet access. | ||
1352 | + * @skb: pointer to skb | ||
1353 | + * @len: len to make read/writeable | ||
1354 | + * Return: 0 on success or negative error | ||
1355 | + */ | ||
1356 | + BPF_FUNC_skb_pull_data, | ||
1357 | + | ||
1358 | + /** | ||
1359 | + * bpf_csum_update(skb, csum) | ||
1360 | + * Adds csum into skb->csum in case of CHECKSUM_COMPLETE. | ||
1361 | + * @skb: pointer to skb | ||
1362 | + * @csum: csum to add | ||
1363 | + * Return: csum on success or negative error | ||
1364 | + */ | ||
1365 | + BPF_FUNC_csum_update, | ||
1366 | + | ||
1367 | + /** | ||
1368 | + * bpf_set_hash_invalid(skb) | ||
1369 | + * Invalidate current skb>hash. | ||
1370 | + * @skb: pointer to skb | ||
1371 | + */ | ||
1372 | + BPF_FUNC_set_hash_invalid, | ||
1373 | + | ||
1374 | __BPF_FUNC_MAX_ID, | ||
1375 | }; | ||
1376 | |||
1377 | diff --git a/tools/include/uapi/linux/fcntl.h b/tools/include/uapi/linux/fcntl.h | ||
1378 | new file mode 100644 | ||
1379 | index 000000000000..beed138bd359 | ||
1380 | --- /dev/null | ||
1381 | +++ b/tools/include/uapi/linux/fcntl.h | ||
1382 | @@ -0,0 +1,67 @@ | ||
1383 | +#ifndef _UAPI_LINUX_FCNTL_H | ||
1384 | +#define _UAPI_LINUX_FCNTL_H | ||
1385 | + | ||
1386 | +#include <asm/fcntl.h> | ||
1387 | + | ||
1388 | +#define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0) | ||
1389 | +#define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1) | ||
1390 | + | ||
1391 | +/* | ||
1392 | + * Cancel a blocking posix lock; internal use only until we expose an | ||
1393 | + * asynchronous lock api to userspace: | ||
1394 | + */ | ||
1395 | +#define F_CANCELLK (F_LINUX_SPECIFIC_BASE + 5) | ||
1396 | + | ||
1397 | +/* Create a file descriptor with FD_CLOEXEC set. */ | ||
1398 | +#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) | ||
1399 | + | ||
1400 | +/* | ||
1401 | + * Request nofications on a directory. | ||
1402 | + * See below for events that may be notified. | ||
1403 | + */ | ||
1404 | +#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2) | ||
1405 | + | ||
1406 | +/* | ||
1407 | + * Set and get of pipe page size array | ||
1408 | + */ | ||
1409 | +#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) | ||
1410 | +#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) | ||
1411 | + | ||
1412 | +/* | ||
1413 | + * Set/Get seals | ||
1414 | + */ | ||
1415 | +#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) | ||
1416 | +#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) | ||
1417 | + | ||
1418 | +/* | ||
1419 | + * Types of seals | ||
1420 | + */ | ||
1421 | +#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ | ||
1422 | +#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ | ||
1423 | +#define F_SEAL_GROW 0x0004 /* prevent file from growing */ | ||
1424 | +#define F_SEAL_WRITE 0x0008 /* prevent writes */ | ||
1425 | +/* (1U << 31) is reserved for signed error codes */ | ||
1426 | + | ||
1427 | +/* | ||
1428 | + * Types of directory notifications that may be requested. | ||
1429 | + */ | ||
1430 | +#define DN_ACCESS 0x00000001 /* File accessed */ | ||
1431 | +#define DN_MODIFY 0x00000002 /* File modified */ | ||
1432 | +#define DN_CREATE 0x00000004 /* File created */ | ||
1433 | +#define DN_DELETE 0x00000008 /* File removed */ | ||
1434 | +#define DN_RENAME 0x00000010 /* File renamed */ | ||
1435 | +#define DN_ATTRIB 0x00000020 /* File changed attibutes */ | ||
1436 | +#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ | ||
1437 | + | ||
1438 | +#define AT_FDCWD -100 /* Special value used to indicate | ||
1439 | + openat should use the current | ||
1440 | + working directory. */ | ||
1441 | +#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ | ||
1442 | +#define AT_REMOVEDIR 0x200 /* Remove directory instead of | ||
1443 | + unlinking file. */ | ||
1444 | +#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ | ||
1445 | +#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ | ||
1446 | +#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ | ||
1447 | + | ||
1448 | + | ||
1449 | +#endif /* _UAPI_LINUX_FCNTL_H */ | ||
1450 | diff --git a/tools/include/uapi/linux/stat.h b/tools/include/uapi/linux/stat.h | ||
1451 | new file mode 100644 | ||
1452 | index 000000000000..7fec7e36d921 | ||
1453 | --- /dev/null | ||
1454 | +++ b/tools/include/uapi/linux/stat.h | ||
1455 | @@ -0,0 +1,45 @@ | ||
1456 | +#ifndef _UAPI_LINUX_STAT_H | ||
1457 | +#define _UAPI_LINUX_STAT_H | ||
1458 | + | ||
1459 | + | ||
1460 | +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) | ||
1461 | + | ||
1462 | +#define S_IFMT 00170000 | ||
1463 | +#define S_IFSOCK 0140000 | ||
1464 | +#define S_IFLNK 0120000 | ||
1465 | +#define S_IFREG 0100000 | ||
1466 | +#define S_IFBLK 0060000 | ||
1467 | +#define S_IFDIR 0040000 | ||
1468 | +#define S_IFCHR 0020000 | ||
1469 | +#define S_IFIFO 0010000 | ||
1470 | +#define S_ISUID 0004000 | ||
1471 | +#define S_ISGID 0002000 | ||
1472 | +#define S_ISVTX 0001000 | ||
1473 | + | ||
1474 | +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) | ||
1475 | +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) | ||
1476 | +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) | ||
1477 | +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) | ||
1478 | +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) | ||
1479 | +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) | ||
1480 | +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) | ||
1481 | + | ||
1482 | +#define S_IRWXU 00700 | ||
1483 | +#define S_IRUSR 00400 | ||
1484 | +#define S_IWUSR 00200 | ||
1485 | +#define S_IXUSR 00100 | ||
1486 | + | ||
1487 | +#define S_IRWXG 00070 | ||
1488 | +#define S_IRGRP 00040 | ||
1489 | +#define S_IWGRP 00020 | ||
1490 | +#define S_IXGRP 00010 | ||
1491 | + | ||
1492 | +#define S_IRWXO 00007 | ||
1493 | +#define S_IROTH 00004 | ||
1494 | +#define S_IWOTH 00002 | ||
1495 | +#define S_IXOTH 00001 | ||
1496 | + | ||
1497 | +#endif | ||
1498 | + | ||
1499 | + | ||
1500 | +#endif /* _UAPI_LINUX_STAT_H */ | ||
1501 | diff --git a/tools/lib/find_bit.c b/tools/lib/find_bit.c | ||
1502 | index 9122a9e80046..6d8b8f22cf55 100644 | ||
1503 | --- a/tools/lib/find_bit.c | ||
1504 | +++ b/tools/lib/find_bit.c | ||
1505 | @@ -82,3 +82,28 @@ unsigned long find_first_bit(const unsigned long *addr, unsigned long size) | ||
1506 | return size; | ||
1507 | } | ||
1508 | #endif | ||
1509 | + | ||
1510 | +#ifndef find_first_zero_bit | ||
1511 | +/* | ||
1512 | + * Find the first cleared bit in a memory region. | ||
1513 | + */ | ||
1514 | +unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) | ||
1515 | +{ | ||
1516 | + unsigned long idx; | ||
1517 | + | ||
1518 | + for (idx = 0; idx * BITS_PER_LONG < size; idx++) { | ||
1519 | + if (addr[idx] != ~0UL) | ||
1520 | + return min(idx * BITS_PER_LONG + ffz(addr[idx]), size); | ||
1521 | + } | ||
1522 | + | ||
1523 | + return size; | ||
1524 | +} | ||
1525 | +#endif | ||
1526 | + | ||
1527 | +#ifndef find_next_zero_bit | ||
1528 | +unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, | ||
1529 | + unsigned long offset) | ||
1530 | +{ | ||
1531 | + return _find_next_bit(addr, size, offset, ~0UL); | ||
1532 | +} | ||
1533 | +#endif | ||
1534 | diff --git a/tools/objtool/Build b/tools/objtool/Build | ||
1535 | index d6cdece5e58b..749becdf5b90 100644 | ||
1536 | --- a/tools/objtool/Build | ||
1537 | +++ b/tools/objtool/Build | ||
1538 | @@ -1,5 +1,9 @@ | ||
1539 | objtool-y += arch/$(SRCARCH)/ | ||
1540 | objtool-y += builtin-check.o | ||
1541 | +objtool-y += builtin-orc.o | ||
1542 | +objtool-y += check.o | ||
1543 | +objtool-y += orc_gen.o | ||
1544 | +objtool-y += orc_dump.o | ||
1545 | objtool-y += elf.o | ||
1546 | objtool-y += special.o | ||
1547 | objtool-y += objtool.o | ||
1548 | diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt | ||
1549 | index 55a60d331f47..3995735a878f 100644 | ||
1550 | --- a/tools/objtool/Documentation/stack-validation.txt | ||
1551 | +++ b/tools/objtool/Documentation/stack-validation.txt | ||
1552 | @@ -11,9 +11,6 @@ analyzes every .o file and ensures the validity of its stack metadata. | ||
1553 | It enforces a set of rules on asm code and C inline assembly code so | ||
1554 | that stack traces can be reliable. | ||
1555 | |||
1556 | -Currently it only checks frame pointer usage, but there are plans to add | ||
1557 | -CFI validation for C files and CFI generation for asm files. | ||
1558 | - | ||
1559 | For each function, it recursively follows all possible code paths and | ||
1560 | validates the correct frame pointer state at each instruction. | ||
1561 | |||
1562 | @@ -23,6 +20,10 @@ alternative execution paths to a given instruction (or set of | ||
1563 | instructions). Similarly, it knows how to follow switch statements, for | ||
1564 | which gcc sometimes uses jump tables. | ||
1565 | |||
1566 | +(Objtool also has an 'orc generate' subcommand which generates debuginfo | ||
1567 | +for the ORC unwinder. See Documentation/x86/orc-unwinder.txt in the | ||
1568 | +kernel tree for more details.) | ||
1569 | + | ||
1570 | |||
1571 | Why do we need stack metadata validation? | ||
1572 | ----------------------------------------- | ||
1573 | @@ -93,62 +94,24 @@ a) More reliable stack traces for frame pointer enabled kernels | ||
1574 | or at the very end of the function after the stack frame has been | ||
1575 | destroyed. This is an inherent limitation of frame pointers. | ||
1576 | |||
1577 | -b) 100% reliable stack traces for DWARF enabled kernels | ||
1578 | - | ||
1579 | - (NOTE: This is not yet implemented) | ||
1580 | - | ||
1581 | - As an alternative to frame pointers, DWARF Call Frame Information | ||
1582 | - (CFI) metadata can be used to walk the stack. Unlike frame pointers, | ||
1583 | - CFI metadata is out of band. So it doesn't affect runtime | ||
1584 | - performance and it can be reliable even when interrupts or exceptions | ||
1585 | - are involved. | ||
1586 | - | ||
1587 | - For C code, gcc automatically generates DWARF CFI metadata. But for | ||
1588 | - asm code, generating CFI is a tedious manual approach which requires | ||
1589 | - manually placed .cfi assembler macros to be scattered throughout the | ||
1590 | - code. It's clumsy and very easy to get wrong, and it makes the real | ||
1591 | - code harder to read. | ||
1592 | - | ||
1593 | - Stacktool will improve this situation in several ways. For code | ||
1594 | - which already has CFI annotations, it will validate them. For code | ||
1595 | - which doesn't have CFI annotations, it will generate them. So an | ||
1596 | - architecture can opt to strip out all the manual .cfi annotations | ||
1597 | - from their asm code and have objtool generate them instead. | ||
1598 | +b) ORC (Oops Rewind Capability) unwind table generation | ||
1599 | |||
1600 | - We might also add a runtime stack validation debug option where we | ||
1601 | - periodically walk the stack from schedule() and/or an NMI to ensure | ||
1602 | - that the stack metadata is sane and that we reach the bottom of the | ||
1603 | - stack. | ||
1604 | + An alternative to frame pointers and DWARF, ORC unwind data can be | ||
1605 | + used to walk the stack. Unlike frame pointers, ORC data is out of | ||
1606 | + band. So it doesn't affect runtime performance and it can be | ||
1607 | + reliable even when interrupts or exceptions are involved. | ||
1608 | |||
1609 | - So the benefit of objtool here will be that external tooling should | ||
1610 | - always show perfect stack traces. And the same will be true for | ||
1611 | - kernel warning/oops traces if the architecture has a runtime DWARF | ||
1612 | - unwinder. | ||
1613 | + For more details, see Documentation/x86/orc-unwinder.txt. | ||
1614 | |||
1615 | c) Higher live patching compatibility rate | ||
1616 | |||
1617 | - (NOTE: This is not yet implemented) | ||
1618 | - | ||
1619 | - Currently with CONFIG_LIVEPATCH there's a basic live patching | ||
1620 | - framework which is safe for roughly 85-90% of "security" fixes. But | ||
1621 | - patches can't have complex features like function dependency or | ||
1622 | - prototype changes, or data structure changes. | ||
1623 | - | ||
1624 | - There's a strong need to support patches which have the more complex | ||
1625 | - features so that the patch compatibility rate for security fixes can | ||
1626 | - eventually approach something resembling 100%. To achieve that, a | ||
1627 | - "consistency model" is needed, which allows tasks to be safely | ||
1628 | - transitioned from an unpatched state to a patched state. | ||
1629 | - | ||
1630 | - One of the key requirements of the currently proposed livepatch | ||
1631 | - consistency model [*] is that it needs to walk the stack of each | ||
1632 | - sleeping task to determine if it can be transitioned to the patched | ||
1633 | - state. If objtool can ensure that stack traces are reliable, this | ||
1634 | - consistency model can be used and the live patching compatibility | ||
1635 | - rate can be improved significantly. | ||
1636 | - | ||
1637 | - [*] https://lkml.kernel.org/r/cover.1423499826.git.jpoimboe@redhat.com | ||
1638 | + Livepatch has an optional "consistency model", which is needed for | ||
1639 | + more complex patches. In order for the consistency model to work, | ||
1640 | + stack traces need to be reliable (or an unreliable condition needs to | ||
1641 | + be detectable). Objtool makes that possible. | ||
1642 | |||
1643 | + For more details, see the livepatch documentation in the Linux kernel | ||
1644 | + source tree at Documentation/livepatch/livepatch.txt. | ||
1645 | |||
1646 | Rules | ||
1647 | ----- | ||
1648 | @@ -201,80 +164,84 @@ To achieve the validation, objtool enforces the following rules: | ||
1649 | return normally. | ||
1650 | |||
1651 | |||
1652 | -Errors in .S files | ||
1653 | ------------------- | ||
1654 | +Objtool warnings | ||
1655 | +---------------- | ||
1656 | + | ||
1657 | +For asm files, if you're getting an error which doesn't make sense, | ||
1658 | +first make sure that the affected code follows the above rules. | ||
1659 | |||
1660 | -If you're getting an error in a compiled .S file which you don't | ||
1661 | -understand, first make sure that the affected code follows the above | ||
1662 | -rules. | ||
1663 | +For C files, the common culprits are inline asm statements and calls to | ||
1664 | +"noreturn" functions. See below for more details. | ||
1665 | + | ||
1666 | +Another possible cause for errors in C code is if the Makefile removes | ||
1667 | +-fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. | ||
1668 | |||
1669 | Here are some examples of common warnings reported by objtool, what | ||
1670 | they mean, and suggestions for how to fix them. | ||
1671 | |||
1672 | |||
1673 | -1. asm_file.o: warning: objtool: func()+0x128: call without frame pointer save/setup | ||
1674 | +1. file.o: warning: objtool: func()+0x128: call without frame pointer save/setup | ||
1675 | |||
1676 | The func() function made a function call without first saving and/or | ||
1677 | - updating the frame pointer. | ||
1678 | - | ||
1679 | - If func() is indeed a callable function, add proper frame pointer | ||
1680 | - logic using the FRAME_BEGIN and FRAME_END macros. Otherwise, remove | ||
1681 | - its ELF function annotation by changing ENDPROC to END. | ||
1682 | - | ||
1683 | - If you're getting this error in a .c file, see the "Errors in .c | ||
1684 | - files" section. | ||
1685 | + updating the frame pointer, and CONFIG_FRAME_POINTER is enabled. | ||
1686 | |||
1687 | + If the error is for an asm file, and func() is indeed a callable | ||
1688 | + function, add proper frame pointer logic using the FRAME_BEGIN and | ||
1689 | + FRAME_END macros. Otherwise, if it's not a callable function, remove | ||
1690 | + its ELF function annotation by changing ENDPROC to END, and instead | ||
1691 | + use the manual unwind hint macros in asm/unwind_hints.h. | ||
1692 | |||
1693 | -2. asm_file.o: warning: objtool: .text+0x53: return instruction outside of a callable function | ||
1694 | + If it's a GCC-compiled .c file, the error may be because the function | ||
1695 | + uses an inline asm() statement which has a "call" instruction. An | ||
1696 | + asm() statement with a call instruction must declare the use of the | ||
1697 | + stack pointer in its output operand. On x86_64, this means adding | ||
1698 | + the ASM_CALL_CONSTRAINT as an output constraint: | ||
1699 | |||
1700 | - A return instruction was detected, but objtool couldn't find a way | ||
1701 | - for a callable function to reach the instruction. | ||
1702 | + asm volatile("call func" : ASM_CALL_CONSTRAINT); | ||
1703 | |||
1704 | - If the return instruction is inside (or reachable from) a callable | ||
1705 | - function, the function needs to be annotated with the ENTRY/ENDPROC | ||
1706 | - macros. | ||
1707 | + Otherwise the stack frame may not get created before the call. | ||
1708 | |||
1709 | - If you _really_ need a return instruction outside of a function, and | ||
1710 | - are 100% sure that it won't affect stack traces, you can tell | ||
1711 | - objtool to ignore it. See the "Adding exceptions" section below. | ||
1712 | |||
1713 | +2. file.o: warning: objtool: .text+0x53: unreachable instruction | ||
1714 | |||
1715 | -3. asm_file.o: warning: objtool: func()+0x9: function has unreachable instruction | ||
1716 | + Objtool couldn't find a code path to reach the instruction. | ||
1717 | |||
1718 | - The instruction lives inside of a callable function, but there's no | ||
1719 | - possible control flow path from the beginning of the function to the | ||
1720 | - instruction. | ||
1721 | + If the error is for an asm file, and the instruction is inside (or | ||
1722 | + reachable from) a callable function, the function should be annotated | ||
1723 | + with the ENTRY/ENDPROC macros (ENDPROC is the important one). | ||
1724 | + Otherwise, the code should probably be annotated with the unwind hint | ||
1725 | + macros in asm/unwind_hints.h so objtool and the unwinder can know the | ||
1726 | + stack state associated with the code. | ||
1727 | |||
1728 | - If the instruction is actually needed, and it's actually in a | ||
1729 | - callable function, ensure that its function is properly annotated | ||
1730 | - with ENTRY/ENDPROC. | ||
1731 | + If you're 100% sure the code won't affect stack traces, or if you're | ||
1732 | + a just a bad person, you can tell objtool to ignore it. See the | ||
1733 | + "Adding exceptions" section below. | ||
1734 | |||
1735 | If it's not actually in a callable function (e.g. kernel entry code), | ||
1736 | change ENDPROC to END. | ||
1737 | |||
1738 | |||
1739 | -4. asm_file.o: warning: objtool: func(): can't find starting instruction | ||
1740 | +4. file.o: warning: objtool: func(): can't find starting instruction | ||
1741 | or | ||
1742 | - asm_file.o: warning: objtool: func()+0x11dd: can't decode instruction | ||
1743 | + file.o: warning: objtool: func()+0x11dd: can't decode instruction | ||
1744 | |||
1745 | - Did you put data in a text section? If so, that can confuse | ||
1746 | + Does the file have data in a text section? If so, that can confuse | ||
1747 | objtool's instruction decoder. Move the data to a more appropriate | ||
1748 | section like .data or .rodata. | ||
1749 | |||
1750 | |||
1751 | -5. asm_file.o: warning: objtool: func()+0x6: kernel entry/exit from callable instruction | ||
1752 | - | ||
1753 | - This is a kernel entry/exit instruction like sysenter or sysret. | ||
1754 | - Such instructions aren't allowed in a callable function, and are most | ||
1755 | - likely part of the kernel entry code. | ||
1756 | +5. file.o: warning: objtool: func()+0x6: unsupported instruction in callable function | ||
1757 | |||
1758 | - If the instruction isn't actually in a callable function, change | ||
1759 | - ENDPROC to END. | ||
1760 | + This is a kernel entry/exit instruction like sysenter or iret. Such | ||
1761 | + instructions aren't allowed in a callable function, and are most | ||
1762 | + likely part of the kernel entry code. They should usually not have | ||
1763 | + the callable function annotation (ENDPROC) and should always be | ||
1764 | + annotated with the unwind hint macros in asm/unwind_hints.h. | ||
1765 | |||
1766 | |||
1767 | -6. asm_file.o: warning: objtool: func()+0x26: sibling call from callable instruction with changed frame pointer | ||
1768 | +6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame | ||
1769 | |||
1770 | - This is a dynamic jump or a jump to an undefined symbol. Stacktool | ||
1771 | + This is a dynamic jump or a jump to an undefined symbol. Objtool | ||
1772 | assumed it's a sibling call and detected that the frame pointer | ||
1773 | wasn't first restored to its original state. | ||
1774 | |||
1775 | @@ -282,24 +249,28 @@ they mean, and suggestions for how to fix them. | ||
1776 | destination code to the local file. | ||
1777 | |||
1778 | If the instruction is not actually in a callable function (e.g. | ||
1779 | - kernel entry code), change ENDPROC to END. | ||
1780 | + kernel entry code), change ENDPROC to END and annotate manually with | ||
1781 | + the unwind hint macros in asm/unwind_hints.h. | ||
1782 | |||
1783 | |||
1784 | -7. asm_file: warning: objtool: func()+0x5c: frame pointer state mismatch | ||
1785 | +7. file: warning: objtool: func()+0x5c: stack state mismatch | ||
1786 | |||
1787 | The instruction's frame pointer state is inconsistent, depending on | ||
1788 | which execution path was taken to reach the instruction. | ||
1789 | |||
1790 | - Make sure the function pushes and sets up the frame pointer (for | ||
1791 | - x86_64, this means rbp) at the beginning of the function and pops it | ||
1792 | - at the end of the function. Also make sure that no other code in the | ||
1793 | - function touches the frame pointer. | ||
1794 | + Make sure that, when CONFIG_FRAME_POINTER is enabled, the function | ||
1795 | + pushes and sets up the frame pointer (for x86_64, this means rbp) at | ||
1796 | + the beginning of the function and pops it at the end of the function. | ||
1797 | + Also make sure that no other code in the function touches the frame | ||
1798 | + pointer. | ||
1799 | |||
1800 | + Another possibility is that the code has some asm or inline asm which | ||
1801 | + does some unusual things to the stack or the frame pointer. In such | ||
1802 | + cases it's probably appropriate to use the unwind hint macros in | ||
1803 | + asm/unwind_hints.h. | ||
1804 | |||
1805 | -Errors in .c files | ||
1806 | ------------------- | ||
1807 | |||
1808 | -1. c_file.o: warning: objtool: funcA() falls through to next function funcB() | ||
1809 | +8. file.o: warning: objtool: funcA() falls through to next function funcB() | ||
1810 | |||
1811 | This means that funcA() doesn't end with a return instruction or an | ||
1812 | unconditional jump, and that objtool has determined that the function | ||
1813 | @@ -318,22 +289,6 @@ Errors in .c files | ||
1814 | might be corrupt due to a gcc bug. For more details, see: | ||
1815 | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 | ||
1816 | |||
1817 | -2. If you're getting any other objtool error in a compiled .c file, it | ||
1818 | - may be because the file uses an asm() statement which has a "call" | ||
1819 | - instruction. An asm() statement with a call instruction must declare | ||
1820 | - the use of the stack pointer in its output operand. For example, on | ||
1821 | - x86_64: | ||
1822 | - | ||
1823 | - register void *__sp asm("rsp"); | ||
1824 | - asm volatile("call func" : "+r" (__sp)); | ||
1825 | - | ||
1826 | - Otherwise the stack frame may not get created before the call. | ||
1827 | - | ||
1828 | -3. Another possible cause for errors in C code is if the Makefile removes | ||
1829 | - -fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. | ||
1830 | - | ||
1831 | -Also see the above section for .S file errors for more information what | ||
1832 | -the individual error messages mean. | ||
1833 | |||
1834 | If the error doesn't seem to make sense, it could be a bug in objtool. | ||
1835 | Feel free to ask the objtool maintainer for help. | ||
1836 | diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile | ||
1837 | index 041b493ad3ab..e6acc281dd37 100644 | ||
1838 | --- a/tools/objtool/Makefile | ||
1839 | +++ b/tools/objtool/Makefile | ||
1840 | @@ -1,3 +1,4 @@ | ||
1841 | +# SPDX-License-Identifier: GPL-2.0 | ||
1842 | include ../scripts/Makefile.include | ||
1843 | include ../scripts/Makefile.arch | ||
1844 | |||
1845 | @@ -6,17 +7,19 @@ ARCH := x86 | ||
1846 | endif | ||
1847 | |||
1848 | # always use the host compiler | ||
1849 | -CC = gcc | ||
1850 | -LD = ld | ||
1851 | -AR = ar | ||
1852 | +HOSTCC ?= gcc | ||
1853 | +HOSTLD ?= ld | ||
1854 | +CC = $(HOSTCC) | ||
1855 | +LD = $(HOSTLD) | ||
1856 | +AR = ar | ||
1857 | |||
1858 | ifeq ($(srctree),) | ||
1859 | -srctree := $(patsubst %/,%,$(dir $(shell pwd))) | ||
1860 | +srctree := $(patsubst %/,%,$(dir $(CURDIR))) | ||
1861 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
1862 | endif | ||
1863 | |||
1864 | SUBCMD_SRCDIR = $(srctree)/tools/lib/subcmd/ | ||
1865 | -LIBSUBCMD_OUTPUT = $(if $(OUTPUT),$(OUTPUT),$(PWD)/) | ||
1866 | +LIBSUBCMD_OUTPUT = $(if $(OUTPUT),$(OUTPUT),$(CURDIR)/) | ||
1867 | LIBSUBCMD = $(LIBSUBCMD_OUTPUT)libsubcmd.a | ||
1868 | |||
1869 | OBJTOOL := $(OUTPUT)objtool | ||
1870 | @@ -24,8 +27,11 @@ OBJTOOL_IN := $(OBJTOOL)-in.o | ||
1871 | |||
1872 | all: $(OBJTOOL) | ||
1873 | |||
1874 | -INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi | ||
1875 | -CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) | ||
1876 | +INCLUDES := -I$(srctree)/tools/include \ | ||
1877 | + -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ | ||
1878 | + -I$(srctree)/tools/objtool/arch/$(ARCH)/include | ||
1879 | +WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed | ||
1880 | +CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) | ||
1881 | LDFLAGS += -lelf $(LIBSUBCMD) | ||
1882 | |||
1883 | # Allow old libelf to be used: | ||
1884 | @@ -39,19 +45,8 @@ include $(srctree)/tools/build/Makefile.include | ||
1885 | $(OBJTOOL_IN): fixdep FORCE | ||
1886 | @$(MAKE) $(build)=objtool | ||
1887 | |||
1888 | -# Busybox's diff doesn't have -I, avoid warning in that case | ||
1889 | -# | ||
1890 | $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) | ||
1891 | - @(diff -I 2>&1 | grep -q 'option requires an argument' && \ | ||
1892 | - test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ | ||
1893 | - diff -I'^#include' arch/x86/insn/insn.c ../../arch/x86/lib/insn.c >/dev/null && \ | ||
1894 | - diff -I'^#include' arch/x86/insn/inat.c ../../arch/x86/lib/inat.c >/dev/null && \ | ||
1895 | - diff arch/x86/insn/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null && \ | ||
1896 | - diff arch/x86/insn/gen-insn-attr-x86.awk ../../arch/x86/tools/gen-insn-attr-x86.awk >/dev/null && \ | ||
1897 | - diff -I'^#include' arch/x86/insn/insn.h ../../arch/x86/include/asm/insn.h >/dev/null && \ | ||
1898 | - diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ | ||
1899 | - diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ | ||
1900 | - || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true | ||
1901 | + @$(CONFIG_SHELL) ./sync-check.sh | ||
1902 | $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ | ||
1903 | |||
1904 | |||
1905 | @@ -61,7 +56,7 @@ $(LIBSUBCMD): fixdep FORCE | ||
1906 | clean: | ||
1907 | $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) | ||
1908 | $(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete | ||
1909 | - $(Q)$(RM) $(OUTPUT)arch/x86/insn/inat-tables.c $(OUTPUT)fixdep | ||
1910 | + $(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep | ||
1911 | |||
1912 | FORCE: | ||
1913 | |||
1914 | diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h | ||
1915 | index f7350fcedc70..b0d7dc3d71b5 100644 | ||
1916 | --- a/tools/objtool/arch.h | ||
1917 | +++ b/tools/objtool/arch.h | ||
1918 | @@ -19,26 +19,64 @@ | ||
1919 | #define _ARCH_H | ||
1920 | |||
1921 | #include <stdbool.h> | ||
1922 | +#include <linux/list.h> | ||
1923 | #include "elf.h" | ||
1924 | +#include "cfi.h" | ||
1925 | |||
1926 | -#define INSN_FP_SAVE 1 | ||
1927 | -#define INSN_FP_SETUP 2 | ||
1928 | -#define INSN_FP_RESTORE 3 | ||
1929 | -#define INSN_JUMP_CONDITIONAL 4 | ||
1930 | -#define INSN_JUMP_UNCONDITIONAL 5 | ||
1931 | -#define INSN_JUMP_DYNAMIC 6 | ||
1932 | -#define INSN_CALL 7 | ||
1933 | -#define INSN_CALL_DYNAMIC 8 | ||
1934 | -#define INSN_RETURN 9 | ||
1935 | -#define INSN_CONTEXT_SWITCH 10 | ||
1936 | -#define INSN_BUG 11 | ||
1937 | -#define INSN_NOP 12 | ||
1938 | -#define INSN_OTHER 13 | ||
1939 | +#define INSN_JUMP_CONDITIONAL 1 | ||
1940 | +#define INSN_JUMP_UNCONDITIONAL 2 | ||
1941 | +#define INSN_JUMP_DYNAMIC 3 | ||
1942 | +#define INSN_CALL 4 | ||
1943 | +#define INSN_CALL_DYNAMIC 5 | ||
1944 | +#define INSN_RETURN 6 | ||
1945 | +#define INSN_CONTEXT_SWITCH 7 | ||
1946 | +#define INSN_STACK 8 | ||
1947 | +#define INSN_BUG 9 | ||
1948 | +#define INSN_NOP 10 | ||
1949 | +#define INSN_OTHER 11 | ||
1950 | #define INSN_LAST INSN_OTHER | ||
1951 | |||
1952 | +enum op_dest_type { | ||
1953 | + OP_DEST_REG, | ||
1954 | + OP_DEST_REG_INDIRECT, | ||
1955 | + OP_DEST_MEM, | ||
1956 | + OP_DEST_PUSH, | ||
1957 | + OP_DEST_LEAVE, | ||
1958 | +}; | ||
1959 | + | ||
1960 | +struct op_dest { | ||
1961 | + enum op_dest_type type; | ||
1962 | + unsigned char reg; | ||
1963 | + int offset; | ||
1964 | +}; | ||
1965 | + | ||
1966 | +enum op_src_type { | ||
1967 | + OP_SRC_REG, | ||
1968 | + OP_SRC_REG_INDIRECT, | ||
1969 | + OP_SRC_CONST, | ||
1970 | + OP_SRC_POP, | ||
1971 | + OP_SRC_ADD, | ||
1972 | + OP_SRC_AND, | ||
1973 | +}; | ||
1974 | + | ||
1975 | +struct op_src { | ||
1976 | + enum op_src_type type; | ||
1977 | + unsigned char reg; | ||
1978 | + int offset; | ||
1979 | +}; | ||
1980 | + | ||
1981 | +struct stack_op { | ||
1982 | + struct op_dest dest; | ||
1983 | + struct op_src src; | ||
1984 | +}; | ||
1985 | + | ||
1986 | +void arch_initial_func_cfi_state(struct cfi_state *state); | ||
1987 | + | ||
1988 | int arch_decode_instruction(struct elf *elf, struct section *sec, | ||
1989 | unsigned long offset, unsigned int maxlen, | ||
1990 | unsigned int *len, unsigned char *type, | ||
1991 | - unsigned long *displacement); | ||
1992 | + unsigned long *immediate, struct stack_op *op); | ||
1993 | + | ||
1994 | +bool arch_callee_saved_reg(unsigned char reg); | ||
1995 | |||
1996 | #endif /* _ARCH_H */ | ||
1997 | diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build | ||
1998 | index debbdb0b5c43..b998412c017d 100644 | ||
1999 | --- a/tools/objtool/arch/x86/Build | ||
2000 | +++ b/tools/objtool/arch/x86/Build | ||
2001 | @@ -1,12 +1,12 @@ | ||
2002 | objtool-y += decode.o | ||
2003 | |||
2004 | -inat_tables_script = arch/x86/insn/gen-insn-attr-x86.awk | ||
2005 | -inat_tables_maps = arch/x86/insn/x86-opcode-map.txt | ||
2006 | +inat_tables_script = arch/x86/tools/gen-insn-attr-x86.awk | ||
2007 | +inat_tables_maps = arch/x86/lib/x86-opcode-map.txt | ||
2008 | |||
2009 | -$(OUTPUT)arch/x86/insn/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) | ||
2010 | +$(OUTPUT)arch/x86/lib/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) | ||
2011 | $(call rule_mkdir) | ||
2012 | $(Q)$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ | ||
2013 | |||
2014 | -$(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/insn/inat-tables.c | ||
2015 | +$(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/lib/inat-tables.c | ||
2016 | |||
2017 | -CFLAGS_decode.o += -I$(OUTPUT)arch/x86/insn | ||
2018 | +CFLAGS_decode.o += -I$(OUTPUT)arch/x86/lib | ||
2019 | diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c | ||
2020 | index 039636ffb6c8..540a209b78ab 100644 | ||
2021 | --- a/tools/objtool/arch/x86/decode.c | ||
2022 | +++ b/tools/objtool/arch/x86/decode.c | ||
2023 | @@ -19,14 +19,25 @@ | ||
2024 | #include <stdlib.h> | ||
2025 | |||
2026 | #define unlikely(cond) (cond) | ||
2027 | -#include "insn/insn.h" | ||
2028 | -#include "insn/inat.c" | ||
2029 | -#include "insn/insn.c" | ||
2030 | +#include <asm/insn.h> | ||
2031 | +#include "lib/inat.c" | ||
2032 | +#include "lib/insn.c" | ||
2033 | |||
2034 | #include "../../elf.h" | ||
2035 | #include "../../arch.h" | ||
2036 | #include "../../warn.h" | ||
2037 | |||
2038 | +static unsigned char op_to_cfi_reg[][2] = { | ||
2039 | + {CFI_AX, CFI_R8}, | ||
2040 | + {CFI_CX, CFI_R9}, | ||
2041 | + {CFI_DX, CFI_R10}, | ||
2042 | + {CFI_BX, CFI_R11}, | ||
2043 | + {CFI_SP, CFI_R12}, | ||
2044 | + {CFI_BP, CFI_R13}, | ||
2045 | + {CFI_SI, CFI_R14}, | ||
2046 | + {CFI_DI, CFI_R15}, | ||
2047 | +}; | ||
2048 | + | ||
2049 | static int is_x86_64(struct elf *elf) | ||
2050 | { | ||
2051 | switch (elf->ehdr.e_machine) { | ||
2052 | @@ -40,24 +51,50 @@ static int is_x86_64(struct elf *elf) | ||
2053 | } | ||
2054 | } | ||
2055 | |||
2056 | +bool arch_callee_saved_reg(unsigned char reg) | ||
2057 | +{ | ||
2058 | + switch (reg) { | ||
2059 | + case CFI_BP: | ||
2060 | + case CFI_BX: | ||
2061 | + case CFI_R12: | ||
2062 | + case CFI_R13: | ||
2063 | + case CFI_R14: | ||
2064 | + case CFI_R15: | ||
2065 | + return true; | ||
2066 | + | ||
2067 | + case CFI_AX: | ||
2068 | + case CFI_CX: | ||
2069 | + case CFI_DX: | ||
2070 | + case CFI_SI: | ||
2071 | + case CFI_DI: | ||
2072 | + case CFI_SP: | ||
2073 | + case CFI_R8: | ||
2074 | + case CFI_R9: | ||
2075 | + case CFI_R10: | ||
2076 | + case CFI_R11: | ||
2077 | + case CFI_RA: | ||
2078 | + default: | ||
2079 | + return false; | ||
2080 | + } | ||
2081 | +} | ||
2082 | + | ||
2083 | int arch_decode_instruction(struct elf *elf, struct section *sec, | ||
2084 | unsigned long offset, unsigned int maxlen, | ||
2085 | unsigned int *len, unsigned char *type, | ||
2086 | - unsigned long *immediate) | ||
2087 | + unsigned long *immediate, struct stack_op *op) | ||
2088 | { | ||
2089 | struct insn insn; | ||
2090 | - int x86_64; | ||
2091 | - unsigned char op1, op2, ext; | ||
2092 | + int x86_64, sign; | ||
2093 | + unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, | ||
2094 | + rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, | ||
2095 | + modrm_reg = 0, sib = 0; | ||
2096 | |||
2097 | x86_64 = is_x86_64(elf); | ||
2098 | if (x86_64 == -1) | ||
2099 | return -1; | ||
2100 | |||
2101 | - insn_init(&insn, (void *)(sec->data + offset), maxlen, x86_64); | ||
2102 | + insn_init(&insn, sec->data->d_buf + offset, maxlen, x86_64); | ||
2103 | insn_get_length(&insn); | ||
2104 | - insn_get_opcode(&insn); | ||
2105 | - insn_get_modrm(&insn); | ||
2106 | - insn_get_immediate(&insn); | ||
2107 | |||
2108 | if (!insn_complete(&insn)) { | ||
2109 | WARN_FUNC("can't decode instruction", sec, offset); | ||
2110 | @@ -73,70 +110,317 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | ||
2111 | op1 = insn.opcode.bytes[0]; | ||
2112 | op2 = insn.opcode.bytes[1]; | ||
2113 | |||
2114 | + if (insn.rex_prefix.nbytes) { | ||
2115 | + rex = insn.rex_prefix.bytes[0]; | ||
2116 | + rex_w = X86_REX_W(rex) >> 3; | ||
2117 | + rex_r = X86_REX_R(rex) >> 2; | ||
2118 | + rex_x = X86_REX_X(rex) >> 1; | ||
2119 | + rex_b = X86_REX_B(rex); | ||
2120 | + } | ||
2121 | + | ||
2122 | + if (insn.modrm.nbytes) { | ||
2123 | + modrm = insn.modrm.bytes[0]; | ||
2124 | + modrm_mod = X86_MODRM_MOD(modrm); | ||
2125 | + modrm_reg = X86_MODRM_REG(modrm); | ||
2126 | + modrm_rm = X86_MODRM_RM(modrm); | ||
2127 | + } | ||
2128 | + | ||
2129 | + if (insn.sib.nbytes) | ||
2130 | + sib = insn.sib.bytes[0]; | ||
2131 | + | ||
2132 | switch (op1) { | ||
2133 | - case 0x55: | ||
2134 | - if (!insn.rex_prefix.nbytes) | ||
2135 | - /* push rbp */ | ||
2136 | - *type = INSN_FP_SAVE; | ||
2137 | + | ||
2138 | + case 0x1: | ||
2139 | + case 0x29: | ||
2140 | + if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { | ||
2141 | + | ||
2142 | + /* add/sub reg, %rsp */ | ||
2143 | + *type = INSN_STACK; | ||
2144 | + op->src.type = OP_SRC_ADD; | ||
2145 | + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
2146 | + op->dest.type = OP_DEST_REG; | ||
2147 | + op->dest.reg = CFI_SP; | ||
2148 | + } | ||
2149 | + break; | ||
2150 | + | ||
2151 | + case 0x50 ... 0x57: | ||
2152 | + | ||
2153 | + /* push reg */ | ||
2154 | + *type = INSN_STACK; | ||
2155 | + op->src.type = OP_SRC_REG; | ||
2156 | + op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; | ||
2157 | + op->dest.type = OP_DEST_PUSH; | ||
2158 | + | ||
2159 | + break; | ||
2160 | + | ||
2161 | + case 0x58 ... 0x5f: | ||
2162 | + | ||
2163 | + /* pop reg */ | ||
2164 | + *type = INSN_STACK; | ||
2165 | + op->src.type = OP_SRC_POP; | ||
2166 | + op->dest.type = OP_DEST_REG; | ||
2167 | + op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; | ||
2168 | + | ||
2169 | break; | ||
2170 | |||
2171 | - case 0x5d: | ||
2172 | - if (!insn.rex_prefix.nbytes) | ||
2173 | - /* pop rbp */ | ||
2174 | - *type = INSN_FP_RESTORE; | ||
2175 | + case 0x68: | ||
2176 | + case 0x6a: | ||
2177 | + /* push immediate */ | ||
2178 | + *type = INSN_STACK; | ||
2179 | + op->src.type = OP_SRC_CONST; | ||
2180 | + op->dest.type = OP_DEST_PUSH; | ||
2181 | break; | ||
2182 | |||
2183 | case 0x70 ... 0x7f: | ||
2184 | *type = INSN_JUMP_CONDITIONAL; | ||
2185 | break; | ||
2186 | |||
2187 | + case 0x81: | ||
2188 | + case 0x83: | ||
2189 | + if (rex != 0x48) | ||
2190 | + break; | ||
2191 | + | ||
2192 | + if (modrm == 0xe4) { | ||
2193 | + /* and imm, %rsp */ | ||
2194 | + *type = INSN_STACK; | ||
2195 | + op->src.type = OP_SRC_AND; | ||
2196 | + op->src.reg = CFI_SP; | ||
2197 | + op->src.offset = insn.immediate.value; | ||
2198 | + op->dest.type = OP_DEST_REG; | ||
2199 | + op->dest.reg = CFI_SP; | ||
2200 | + break; | ||
2201 | + } | ||
2202 | + | ||
2203 | + if (modrm == 0xc4) | ||
2204 | + sign = 1; | ||
2205 | + else if (modrm == 0xec) | ||
2206 | + sign = -1; | ||
2207 | + else | ||
2208 | + break; | ||
2209 | + | ||
2210 | + /* add/sub imm, %rsp */ | ||
2211 | + *type = INSN_STACK; | ||
2212 | + op->src.type = OP_SRC_ADD; | ||
2213 | + op->src.reg = CFI_SP; | ||
2214 | + op->src.offset = insn.immediate.value * sign; | ||
2215 | + op->dest.type = OP_DEST_REG; | ||
2216 | + op->dest.reg = CFI_SP; | ||
2217 | + break; | ||
2218 | + | ||
2219 | case 0x89: | ||
2220 | - if (insn.rex_prefix.nbytes == 1 && | ||
2221 | - insn.rex_prefix.bytes[0] == 0x48 && | ||
2222 | - insn.modrm.nbytes && insn.modrm.bytes[0] == 0xe5) | ||
2223 | - /* mov rsp, rbp */ | ||
2224 | - *type = INSN_FP_SETUP; | ||
2225 | + if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) { | ||
2226 | + | ||
2227 | + /* mov %rsp, reg */ | ||
2228 | + *type = INSN_STACK; | ||
2229 | + op->src.type = OP_SRC_REG; | ||
2230 | + op->src.reg = CFI_SP; | ||
2231 | + op->dest.type = OP_DEST_REG; | ||
2232 | + op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; | ||
2233 | + break; | ||
2234 | + } | ||
2235 | + | ||
2236 | + if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { | ||
2237 | + | ||
2238 | + /* mov reg, %rsp */ | ||
2239 | + *type = INSN_STACK; | ||
2240 | + op->src.type = OP_SRC_REG; | ||
2241 | + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
2242 | + op->dest.type = OP_DEST_REG; | ||
2243 | + op->dest.reg = CFI_SP; | ||
2244 | + break; | ||
2245 | + } | ||
2246 | + | ||
2247 | + /* fallthrough */ | ||
2248 | + case 0x88: | ||
2249 | + if (!rex_b && | ||
2250 | + (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) { | ||
2251 | + | ||
2252 | + /* mov reg, disp(%rbp) */ | ||
2253 | + *type = INSN_STACK; | ||
2254 | + op->src.type = OP_SRC_REG; | ||
2255 | + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
2256 | + op->dest.type = OP_DEST_REG_INDIRECT; | ||
2257 | + op->dest.reg = CFI_BP; | ||
2258 | + op->dest.offset = insn.displacement.value; | ||
2259 | + | ||
2260 | + } else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) { | ||
2261 | + | ||
2262 | + /* mov reg, disp(%rsp) */ | ||
2263 | + *type = INSN_STACK; | ||
2264 | + op->src.type = OP_SRC_REG; | ||
2265 | + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
2266 | + op->dest.type = OP_DEST_REG_INDIRECT; | ||
2267 | + op->dest.reg = CFI_SP; | ||
2268 | + op->dest.offset = insn.displacement.value; | ||
2269 | + } | ||
2270 | + | ||
2271 | + break; | ||
2272 | + | ||
2273 | + case 0x8b: | ||
2274 | + if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) { | ||
2275 | + | ||
2276 | + /* mov disp(%rbp), reg */ | ||
2277 | + *type = INSN_STACK; | ||
2278 | + op->src.type = OP_SRC_REG_INDIRECT; | ||
2279 | + op->src.reg = CFI_BP; | ||
2280 | + op->src.offset = insn.displacement.value; | ||
2281 | + op->dest.type = OP_DEST_REG; | ||
2282 | + op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
2283 | + | ||
2284 | + } else if (rex_w && !rex_b && sib == 0x24 && | ||
2285 | + modrm_mod != 3 && modrm_rm == 4) { | ||
2286 | + | ||
2287 | + /* mov disp(%rsp), reg */ | ||
2288 | + *type = INSN_STACK; | ||
2289 | + op->src.type = OP_SRC_REG_INDIRECT; | ||
2290 | + op->src.reg = CFI_SP; | ||
2291 | + op->src.offset = insn.displacement.value; | ||
2292 | + op->dest.type = OP_DEST_REG; | ||
2293 | + op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
2294 | + } | ||
2295 | + | ||
2296 | break; | ||
2297 | |||
2298 | case 0x8d: | ||
2299 | - if (insn.rex_prefix.nbytes && | ||
2300 | - insn.rex_prefix.bytes[0] == 0x48 && | ||
2301 | - insn.modrm.nbytes && insn.modrm.bytes[0] == 0x2c && | ||
2302 | - insn.sib.nbytes && insn.sib.bytes[0] == 0x24) | ||
2303 | - /* lea %(rsp), %rbp */ | ||
2304 | - *type = INSN_FP_SETUP; | ||
2305 | + if (sib == 0x24 && rex_w && !rex_b && !rex_x) { | ||
2306 | + | ||
2307 | + *type = INSN_STACK; | ||
2308 | + if (!insn.displacement.value) { | ||
2309 | + /* lea (%rsp), reg */ | ||
2310 | + op->src.type = OP_SRC_REG; | ||
2311 | + } else { | ||
2312 | + /* lea disp(%rsp), reg */ | ||
2313 | + op->src.type = OP_SRC_ADD; | ||
2314 | + op->src.offset = insn.displacement.value; | ||
2315 | + } | ||
2316 | + op->src.reg = CFI_SP; | ||
2317 | + op->dest.type = OP_DEST_REG; | ||
2318 | + op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; | ||
2319 | + | ||
2320 | + } else if (rex == 0x48 && modrm == 0x65) { | ||
2321 | + | ||
2322 | + /* lea disp(%rbp), %rsp */ | ||
2323 | + *type = INSN_STACK; | ||
2324 | + op->src.type = OP_SRC_ADD; | ||
2325 | + op->src.reg = CFI_BP; | ||
2326 | + op->src.offset = insn.displacement.value; | ||
2327 | + op->dest.type = OP_DEST_REG; | ||
2328 | + op->dest.reg = CFI_SP; | ||
2329 | + | ||
2330 | + } else if (rex == 0x49 && modrm == 0x62 && | ||
2331 | + insn.displacement.value == -8) { | ||
2332 | + | ||
2333 | + /* | ||
2334 | + * lea -0x8(%r10), %rsp | ||
2335 | + * | ||
2336 | + * Restoring rsp back to its original value after a | ||
2337 | + * stack realignment. | ||
2338 | + */ | ||
2339 | + *type = INSN_STACK; | ||
2340 | + op->src.type = OP_SRC_ADD; | ||
2341 | + op->src.reg = CFI_R10; | ||
2342 | + op->src.offset = -8; | ||
2343 | + op->dest.type = OP_DEST_REG; | ||
2344 | + op->dest.reg = CFI_SP; | ||
2345 | + | ||
2346 | + } else if (rex == 0x49 && modrm == 0x65 && | ||
2347 | + insn.displacement.value == -16) { | ||
2348 | + | ||
2349 | + /* | ||
2350 | + * lea -0x10(%r13), %rsp | ||
2351 | + * | ||
2352 | + * Restoring rsp back to its original value after a | ||
2353 | + * stack realignment. | ||
2354 | + */ | ||
2355 | + *type = INSN_STACK; | ||
2356 | + op->src.type = OP_SRC_ADD; | ||
2357 | + op->src.reg = CFI_R13; | ||
2358 | + op->src.offset = -16; | ||
2359 | + op->dest.type = OP_DEST_REG; | ||
2360 | + op->dest.reg = CFI_SP; | ||
2361 | + } | ||
2362 | + | ||
2363 | + break; | ||
2364 | + | ||
2365 | + case 0x8f: | ||
2366 | + /* pop to mem */ | ||
2367 | + *type = INSN_STACK; | ||
2368 | + op->src.type = OP_SRC_POP; | ||
2369 | + op->dest.type = OP_DEST_MEM; | ||
2370 | break; | ||
2371 | |||
2372 | case 0x90: | ||
2373 | *type = INSN_NOP; | ||
2374 | break; | ||
2375 | |||
2376 | + case 0x9c: | ||
2377 | + /* pushf */ | ||
2378 | + *type = INSN_STACK; | ||
2379 | + op->src.type = OP_SRC_CONST; | ||
2380 | + op->dest.type = OP_DEST_PUSH; | ||
2381 | + break; | ||
2382 | + | ||
2383 | + case 0x9d: | ||
2384 | + /* popf */ | ||
2385 | + *type = INSN_STACK; | ||
2386 | + op->src.type = OP_SRC_POP; | ||
2387 | + op->dest.type = OP_DEST_MEM; | ||
2388 | + break; | ||
2389 | + | ||
2390 | case 0x0f: | ||
2391 | - if (op2 >= 0x80 && op2 <= 0x8f) | ||
2392 | + | ||
2393 | + if (op2 >= 0x80 && op2 <= 0x8f) { | ||
2394 | + | ||
2395 | *type = INSN_JUMP_CONDITIONAL; | ||
2396 | - else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || | ||
2397 | - op2 == 0x35) | ||
2398 | + | ||
2399 | + } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || | ||
2400 | + op2 == 0x35) { | ||
2401 | + | ||
2402 | /* sysenter, sysret */ | ||
2403 | *type = INSN_CONTEXT_SWITCH; | ||
2404 | - else if (op2 == 0x0b || op2 == 0xb9) | ||
2405 | + | ||
2406 | + } else if (op2 == 0x0b || op2 == 0xb9) { | ||
2407 | + | ||
2408 | /* ud2 */ | ||
2409 | *type = INSN_BUG; | ||
2410 | - else if (op2 == 0x0d || op2 == 0x1f) | ||
2411 | + | ||
2412 | + } else if (op2 == 0x0d || op2 == 0x1f) { | ||
2413 | + | ||
2414 | /* nopl/nopw */ | ||
2415 | *type = INSN_NOP; | ||
2416 | - else if (op2 == 0x01 && insn.modrm.nbytes && | ||
2417 | - (insn.modrm.bytes[0] == 0xc2 || | ||
2418 | - insn.modrm.bytes[0] == 0xd8)) | ||
2419 | - /* vmlaunch, vmrun */ | ||
2420 | - *type = INSN_CONTEXT_SWITCH; | ||
2421 | + | ||
2422 | + } else if (op2 == 0xa0 || op2 == 0xa8) { | ||
2423 | + | ||
2424 | + /* push fs/gs */ | ||
2425 | + *type = INSN_STACK; | ||
2426 | + op->src.type = OP_SRC_CONST; | ||
2427 | + op->dest.type = OP_DEST_PUSH; | ||
2428 | + | ||
2429 | + } else if (op2 == 0xa1 || op2 == 0xa9) { | ||
2430 | + | ||
2431 | + /* pop fs/gs */ | ||
2432 | + *type = INSN_STACK; | ||
2433 | + op->src.type = OP_SRC_POP; | ||
2434 | + op->dest.type = OP_DEST_MEM; | ||
2435 | + } | ||
2436 | |||
2437 | break; | ||
2438 | |||
2439 | - case 0xc9: /* leave */ | ||
2440 | - *type = INSN_FP_RESTORE; | ||
2441 | + case 0xc9: | ||
2442 | + /* | ||
2443 | + * leave | ||
2444 | + * | ||
2445 | + * equivalent to: | ||
2446 | + * mov bp, sp | ||
2447 | + * pop bp | ||
2448 | + */ | ||
2449 | + *type = INSN_STACK; | ||
2450 | + op->dest.type = OP_DEST_LEAVE; | ||
2451 | + | ||
2452 | break; | ||
2453 | |||
2454 | - case 0xe3: /* jecxz/jrcxz */ | ||
2455 | + case 0xe3: | ||
2456 | + /* jecxz/jrcxz */ | ||
2457 | *type = INSN_JUMP_CONDITIONAL; | ||
2458 | break; | ||
2459 | |||
2460 | @@ -161,14 +445,27 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | ||
2461 | break; | ||
2462 | |||
2463 | case 0xff: | ||
2464 | - ext = X86_MODRM_REG(insn.modrm.bytes[0]); | ||
2465 | - if (ext == 2 || ext == 3) | ||
2466 | + if (modrm_reg == 2 || modrm_reg == 3) | ||
2467 | + | ||
2468 | *type = INSN_CALL_DYNAMIC; | ||
2469 | - else if (ext == 4) | ||
2470 | + | ||
2471 | + else if (modrm_reg == 4) | ||
2472 | + | ||
2473 | *type = INSN_JUMP_DYNAMIC; | ||
2474 | - else if (ext == 5) /*jmpf */ | ||
2475 | + | ||
2476 | + else if (modrm_reg == 5) | ||
2477 | + | ||
2478 | + /* jmpf */ | ||
2479 | *type = INSN_CONTEXT_SWITCH; | ||
2480 | |||
2481 | + else if (modrm_reg == 6) { | ||
2482 | + | ||
2483 | + /* push from mem */ | ||
2484 | + *type = INSN_STACK; | ||
2485 | + op->src.type = OP_SRC_CONST; | ||
2486 | + op->dest.type = OP_DEST_PUSH; | ||
2487 | + } | ||
2488 | + | ||
2489 | break; | ||
2490 | |||
2491 | default: | ||
2492 | @@ -179,3 +476,21 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | ||
2493 | |||
2494 | return 0; | ||
2495 | } | ||
2496 | + | ||
2497 | +void arch_initial_func_cfi_state(struct cfi_state *state) | ||
2498 | +{ | ||
2499 | + int i; | ||
2500 | + | ||
2501 | + for (i = 0; i < CFI_NUM_REGS; i++) { | ||
2502 | + state->regs[i].base = CFI_UNDEFINED; | ||
2503 | + state->regs[i].offset = 0; | ||
2504 | + } | ||
2505 | + | ||
2506 | + /* initial CFA (call frame address) */ | ||
2507 | + state->cfa.base = CFI_SP; | ||
2508 | + state->cfa.offset = 8; | ||
2509 | + | ||
2510 | + /* initial RA (return address) */ | ||
2511 | + state->regs[16].base = CFI_CFA; | ||
2512 | + state->regs[16].offset = -8; | ||
2513 | +} | ||
2514 | diff --git a/tools/objtool/arch/x86/include/asm/inat.h b/tools/objtool/arch/x86/include/asm/inat.h | ||
2515 | new file mode 100644 | ||
2516 | index 000000000000..02aff0867211 | ||
2517 | --- /dev/null | ||
2518 | +++ b/tools/objtool/arch/x86/include/asm/inat.h | ||
2519 | @@ -0,0 +1,234 @@ | ||
2520 | +#ifndef _ASM_X86_INAT_H | ||
2521 | +#define _ASM_X86_INAT_H | ||
2522 | +/* | ||
2523 | + * x86 instruction attributes | ||
2524 | + * | ||
2525 | + * Written by Masami Hiramatsu <mhiramat@redhat.com> | ||
2526 | + * | ||
2527 | + * This program is free software; you can redistribute it and/or modify | ||
2528 | + * it under the terms of the GNU General Public License as published by | ||
2529 | + * the Free Software Foundation; either version 2 of the License, or | ||
2530 | + * (at your option) any later version. | ||
2531 | + * | ||
2532 | + * This program is distributed in the hope that it will be useful, | ||
2533 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2534 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2535 | + * GNU General Public License for more details. | ||
2536 | + * | ||
2537 | + * You should have received a copy of the GNU General Public License | ||
2538 | + * along with this program; if not, write to the Free Software | ||
2539 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
2540 | + * | ||
2541 | + */ | ||
2542 | +#include <asm/inat_types.h> | ||
2543 | + | ||
2544 | +/* | ||
2545 | + * Internal bits. Don't use bitmasks directly, because these bits are | ||
2546 | + * unstable. You should use checking functions. | ||
2547 | + */ | ||
2548 | + | ||
2549 | +#define INAT_OPCODE_TABLE_SIZE 256 | ||
2550 | +#define INAT_GROUP_TABLE_SIZE 8 | ||
2551 | + | ||
2552 | +/* Legacy last prefixes */ | ||
2553 | +#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ | ||
2554 | +#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ | ||
2555 | +#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ | ||
2556 | +/* Other Legacy prefixes */ | ||
2557 | +#define INAT_PFX_LOCK 4 /* 0xF0 */ | ||
2558 | +#define INAT_PFX_CS 5 /* 0x2E */ | ||
2559 | +#define INAT_PFX_DS 6 /* 0x3E */ | ||
2560 | +#define INAT_PFX_ES 7 /* 0x26 */ | ||
2561 | +#define INAT_PFX_FS 8 /* 0x64 */ | ||
2562 | +#define INAT_PFX_GS 9 /* 0x65 */ | ||
2563 | +#define INAT_PFX_SS 10 /* 0x36 */ | ||
2564 | +#define INAT_PFX_ADDRSZ 11 /* 0x67 */ | ||
2565 | +/* x86-64 REX prefix */ | ||
2566 | +#define INAT_PFX_REX 12 /* 0x4X */ | ||
2567 | +/* AVX VEX prefixes */ | ||
2568 | +#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ | ||
2569 | +#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ | ||
2570 | +#define INAT_PFX_EVEX 15 /* EVEX prefix */ | ||
2571 | + | ||
2572 | +#define INAT_LSTPFX_MAX 3 | ||
2573 | +#define INAT_LGCPFX_MAX 11 | ||
2574 | + | ||
2575 | +/* Immediate size */ | ||
2576 | +#define INAT_IMM_BYTE 1 | ||
2577 | +#define INAT_IMM_WORD 2 | ||
2578 | +#define INAT_IMM_DWORD 3 | ||
2579 | +#define INAT_IMM_QWORD 4 | ||
2580 | +#define INAT_IMM_PTR 5 | ||
2581 | +#define INAT_IMM_VWORD32 6 | ||
2582 | +#define INAT_IMM_VWORD 7 | ||
2583 | + | ||
2584 | +/* Legacy prefix */ | ||
2585 | +#define INAT_PFX_OFFS 0 | ||
2586 | +#define INAT_PFX_BITS 4 | ||
2587 | +#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) | ||
2588 | +#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) | ||
2589 | +/* Escape opcodes */ | ||
2590 | +#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) | ||
2591 | +#define INAT_ESC_BITS 2 | ||
2592 | +#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) | ||
2593 | +#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) | ||
2594 | +/* Group opcodes (1-16) */ | ||
2595 | +#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) | ||
2596 | +#define INAT_GRP_BITS 5 | ||
2597 | +#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) | ||
2598 | +#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) | ||
2599 | +/* Immediates */ | ||
2600 | +#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) | ||
2601 | +#define INAT_IMM_BITS 3 | ||
2602 | +#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) | ||
2603 | +/* Flags */ | ||
2604 | +#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) | ||
2605 | +#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) | ||
2606 | +#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) | ||
2607 | +#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) | ||
2608 | +#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) | ||
2609 | +#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) | ||
2610 | +#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) | ||
2611 | +#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) | ||
2612 | +#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) | ||
2613 | +/* Attribute making macros for attribute tables */ | ||
2614 | +#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) | ||
2615 | +#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) | ||
2616 | +#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) | ||
2617 | +#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) | ||
2618 | + | ||
2619 | +/* Attribute search APIs */ | ||
2620 | +extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); | ||
2621 | +extern int inat_get_last_prefix_id(insn_byte_t last_pfx); | ||
2622 | +extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, | ||
2623 | + int lpfx_id, | ||
2624 | + insn_attr_t esc_attr); | ||
2625 | +extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, | ||
2626 | + int lpfx_id, | ||
2627 | + insn_attr_t esc_attr); | ||
2628 | +extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, | ||
2629 | + insn_byte_t vex_m, | ||
2630 | + insn_byte_t vex_pp); | ||
2631 | + | ||
2632 | +/* Attribute checking functions */ | ||
2633 | +static inline int inat_is_legacy_prefix(insn_attr_t attr) | ||
2634 | +{ | ||
2635 | + attr &= INAT_PFX_MASK; | ||
2636 | + return attr && attr <= INAT_LGCPFX_MAX; | ||
2637 | +} | ||
2638 | + | ||
2639 | +static inline int inat_is_address_size_prefix(insn_attr_t attr) | ||
2640 | +{ | ||
2641 | + return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; | ||
2642 | +} | ||
2643 | + | ||
2644 | +static inline int inat_is_operand_size_prefix(insn_attr_t attr) | ||
2645 | +{ | ||
2646 | + return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; | ||
2647 | +} | ||
2648 | + | ||
2649 | +static inline int inat_is_rex_prefix(insn_attr_t attr) | ||
2650 | +{ | ||
2651 | + return (attr & INAT_PFX_MASK) == INAT_PFX_REX; | ||
2652 | +} | ||
2653 | + | ||
2654 | +static inline int inat_last_prefix_id(insn_attr_t attr) | ||
2655 | +{ | ||
2656 | + if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) | ||
2657 | + return 0; | ||
2658 | + else | ||
2659 | + return attr & INAT_PFX_MASK; | ||
2660 | +} | ||
2661 | + | ||
2662 | +static inline int inat_is_vex_prefix(insn_attr_t attr) | ||
2663 | +{ | ||
2664 | + attr &= INAT_PFX_MASK; | ||
2665 | + return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || | ||
2666 | + attr == INAT_PFX_EVEX; | ||
2667 | +} | ||
2668 | + | ||
2669 | +static inline int inat_is_evex_prefix(insn_attr_t attr) | ||
2670 | +{ | ||
2671 | + return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; | ||
2672 | +} | ||
2673 | + | ||
2674 | +static inline int inat_is_vex3_prefix(insn_attr_t attr) | ||
2675 | +{ | ||
2676 | + return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; | ||
2677 | +} | ||
2678 | + | ||
2679 | +static inline int inat_is_escape(insn_attr_t attr) | ||
2680 | +{ | ||
2681 | + return attr & INAT_ESC_MASK; | ||
2682 | +} | ||
2683 | + | ||
2684 | +static inline int inat_escape_id(insn_attr_t attr) | ||
2685 | +{ | ||
2686 | + return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; | ||
2687 | +} | ||
2688 | + | ||
2689 | +static inline int inat_is_group(insn_attr_t attr) | ||
2690 | +{ | ||
2691 | + return attr & INAT_GRP_MASK; | ||
2692 | +} | ||
2693 | + | ||
2694 | +static inline int inat_group_id(insn_attr_t attr) | ||
2695 | +{ | ||
2696 | + return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; | ||
2697 | +} | ||
2698 | + | ||
2699 | +static inline int inat_group_common_attribute(insn_attr_t attr) | ||
2700 | +{ | ||
2701 | + return attr & ~INAT_GRP_MASK; | ||
2702 | +} | ||
2703 | + | ||
2704 | +static inline int inat_has_immediate(insn_attr_t attr) | ||
2705 | +{ | ||
2706 | + return attr & INAT_IMM_MASK; | ||
2707 | +} | ||
2708 | + | ||
2709 | +static inline int inat_immediate_size(insn_attr_t attr) | ||
2710 | +{ | ||
2711 | + return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; | ||
2712 | +} | ||
2713 | + | ||
2714 | +static inline int inat_has_modrm(insn_attr_t attr) | ||
2715 | +{ | ||
2716 | + return attr & INAT_MODRM; | ||
2717 | +} | ||
2718 | + | ||
2719 | +static inline int inat_is_force64(insn_attr_t attr) | ||
2720 | +{ | ||
2721 | + return attr & INAT_FORCE64; | ||
2722 | +} | ||
2723 | + | ||
2724 | +static inline int inat_has_second_immediate(insn_attr_t attr) | ||
2725 | +{ | ||
2726 | + return attr & INAT_SCNDIMM; | ||
2727 | +} | ||
2728 | + | ||
2729 | +static inline int inat_has_moffset(insn_attr_t attr) | ||
2730 | +{ | ||
2731 | + return attr & INAT_MOFFSET; | ||
2732 | +} | ||
2733 | + | ||
2734 | +static inline int inat_has_variant(insn_attr_t attr) | ||
2735 | +{ | ||
2736 | + return attr & INAT_VARIANT; | ||
2737 | +} | ||
2738 | + | ||
2739 | +static inline int inat_accept_vex(insn_attr_t attr) | ||
2740 | +{ | ||
2741 | + return attr & INAT_VEXOK; | ||
2742 | +} | ||
2743 | + | ||
2744 | +static inline int inat_must_vex(insn_attr_t attr) | ||
2745 | +{ | ||
2746 | + return attr & (INAT_VEXONLY | INAT_EVEXONLY); | ||
2747 | +} | ||
2748 | + | ||
2749 | +static inline int inat_must_evex(insn_attr_t attr) | ||
2750 | +{ | ||
2751 | + return attr & INAT_EVEXONLY; | ||
2752 | +} | ||
2753 | +#endif | ||
2754 | diff --git a/tools/objtool/arch/x86/include/asm/inat_types.h b/tools/objtool/arch/x86/include/asm/inat_types.h | ||
2755 | new file mode 100644 | ||
2756 | index 000000000000..cb3c20ce39cf | ||
2757 | --- /dev/null | ||
2758 | +++ b/tools/objtool/arch/x86/include/asm/inat_types.h | ||
2759 | @@ -0,0 +1,29 @@ | ||
2760 | +#ifndef _ASM_X86_INAT_TYPES_H | ||
2761 | +#define _ASM_X86_INAT_TYPES_H | ||
2762 | +/* | ||
2763 | + * x86 instruction attributes | ||
2764 | + * | ||
2765 | + * Written by Masami Hiramatsu <mhiramat@redhat.com> | ||
2766 | + * | ||
2767 | + * This program is free software; you can redistribute it and/or modify | ||
2768 | + * it under the terms of the GNU General Public License as published by | ||
2769 | + * the Free Software Foundation; either version 2 of the License, or | ||
2770 | + * (at your option) any later version. | ||
2771 | + * | ||
2772 | + * This program is distributed in the hope that it will be useful, | ||
2773 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2774 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2775 | + * GNU General Public License for more details. | ||
2776 | + * | ||
2777 | + * You should have received a copy of the GNU General Public License | ||
2778 | + * along with this program; if not, write to the Free Software | ||
2779 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
2780 | + * | ||
2781 | + */ | ||
2782 | + | ||
2783 | +/* Instruction attributes */ | ||
2784 | +typedef unsigned int insn_attr_t; | ||
2785 | +typedef unsigned char insn_byte_t; | ||
2786 | +typedef signed int insn_value_t; | ||
2787 | + | ||
2788 | +#endif | ||
2789 | diff --git a/tools/objtool/arch/x86/include/asm/insn.h b/tools/objtool/arch/x86/include/asm/insn.h | ||
2790 | new file mode 100644 | ||
2791 | index 000000000000..b3e32b010ab1 | ||
2792 | --- /dev/null | ||
2793 | +++ b/tools/objtool/arch/x86/include/asm/insn.h | ||
2794 | @@ -0,0 +1,211 @@ | ||
2795 | +#ifndef _ASM_X86_INSN_H | ||
2796 | +#define _ASM_X86_INSN_H | ||
2797 | +/* | ||
2798 | + * x86 instruction analysis | ||
2799 | + * | ||
2800 | + * This program is free software; you can redistribute it and/or modify | ||
2801 | + * it under the terms of the GNU General Public License as published by | ||
2802 | + * the Free Software Foundation; either version 2 of the License, or | ||
2803 | + * (at your option) any later version. | ||
2804 | + * | ||
2805 | + * This program is distributed in the hope that it will be useful, | ||
2806 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2807 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2808 | + * GNU General Public License for more details. | ||
2809 | + * | ||
2810 | + * You should have received a copy of the GNU General Public License | ||
2811 | + * along with this program; if not, write to the Free Software | ||
2812 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
2813 | + * | ||
2814 | + * Copyright (C) IBM Corporation, 2009 | ||
2815 | + */ | ||
2816 | + | ||
2817 | +/* insn_attr_t is defined in inat.h */ | ||
2818 | +#include <asm/inat.h> | ||
2819 | + | ||
2820 | +struct insn_field { | ||
2821 | + union { | ||
2822 | + insn_value_t value; | ||
2823 | + insn_byte_t bytes[4]; | ||
2824 | + }; | ||
2825 | + /* !0 if we've run insn_get_xxx() for this field */ | ||
2826 | + unsigned char got; | ||
2827 | + unsigned char nbytes; | ||
2828 | +}; | ||
2829 | + | ||
2830 | +struct insn { | ||
2831 | + struct insn_field prefixes; /* | ||
2832 | + * Prefixes | ||
2833 | + * prefixes.bytes[3]: last prefix | ||
2834 | + */ | ||
2835 | + struct insn_field rex_prefix; /* REX prefix */ | ||
2836 | + struct insn_field vex_prefix; /* VEX prefix */ | ||
2837 | + struct insn_field opcode; /* | ||
2838 | + * opcode.bytes[0]: opcode1 | ||
2839 | + * opcode.bytes[1]: opcode2 | ||
2840 | + * opcode.bytes[2]: opcode3 | ||
2841 | + */ | ||
2842 | + struct insn_field modrm; | ||
2843 | + struct insn_field sib; | ||
2844 | + struct insn_field displacement; | ||
2845 | + union { | ||
2846 | + struct insn_field immediate; | ||
2847 | + struct insn_field moffset1; /* for 64bit MOV */ | ||
2848 | + struct insn_field immediate1; /* for 64bit imm or off16/32 */ | ||
2849 | + }; | ||
2850 | + union { | ||
2851 | + struct insn_field moffset2; /* for 64bit MOV */ | ||
2852 | + struct insn_field immediate2; /* for 64bit imm or seg16 */ | ||
2853 | + }; | ||
2854 | + | ||
2855 | + insn_attr_t attr; | ||
2856 | + unsigned char opnd_bytes; | ||
2857 | + unsigned char addr_bytes; | ||
2858 | + unsigned char length; | ||
2859 | + unsigned char x86_64; | ||
2860 | + | ||
2861 | + const insn_byte_t *kaddr; /* kernel address of insn to analyze */ | ||
2862 | + const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ | ||
2863 | + const insn_byte_t *next_byte; | ||
2864 | +}; | ||
2865 | + | ||
2866 | +#define MAX_INSN_SIZE 15 | ||
2867 | + | ||
2868 | +#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) | ||
2869 | +#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) | ||
2870 | +#define X86_MODRM_RM(modrm) ((modrm) & 0x07) | ||
2871 | + | ||
2872 | +#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) | ||
2873 | +#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) | ||
2874 | +#define X86_SIB_BASE(sib) ((sib) & 0x07) | ||
2875 | + | ||
2876 | +#define X86_REX_W(rex) ((rex) & 8) | ||
2877 | +#define X86_REX_R(rex) ((rex) & 4) | ||
2878 | +#define X86_REX_X(rex) ((rex) & 2) | ||
2879 | +#define X86_REX_B(rex) ((rex) & 1) | ||
2880 | + | ||
2881 | +/* VEX bit flags */ | ||
2882 | +#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ | ||
2883 | +#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ | ||
2884 | +#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ | ||
2885 | +#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ | ||
2886 | +#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ | ||
2887 | +/* VEX bit fields */ | ||
2888 | +#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ | ||
2889 | +#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ | ||
2890 | +#define X86_VEX2_M 1 /* VEX2.M always 1 */ | ||
2891 | +#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ | ||
2892 | +#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ | ||
2893 | +#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ | ||
2894 | + | ||
2895 | +extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); | ||
2896 | +extern void insn_get_prefixes(struct insn *insn); | ||
2897 | +extern void insn_get_opcode(struct insn *insn); | ||
2898 | +extern void insn_get_modrm(struct insn *insn); | ||
2899 | +extern void insn_get_sib(struct insn *insn); | ||
2900 | +extern void insn_get_displacement(struct insn *insn); | ||
2901 | +extern void insn_get_immediate(struct insn *insn); | ||
2902 | +extern void insn_get_length(struct insn *insn); | ||
2903 | + | ||
2904 | +/* Attribute will be determined after getting ModRM (for opcode groups) */ | ||
2905 | +static inline void insn_get_attribute(struct insn *insn) | ||
2906 | +{ | ||
2907 | + insn_get_modrm(insn); | ||
2908 | +} | ||
2909 | + | ||
2910 | +/* Instruction uses RIP-relative addressing */ | ||
2911 | +extern int insn_rip_relative(struct insn *insn); | ||
2912 | + | ||
2913 | +/* Init insn for kernel text */ | ||
2914 | +static inline void kernel_insn_init(struct insn *insn, | ||
2915 | + const void *kaddr, int buf_len) | ||
2916 | +{ | ||
2917 | +#ifdef CONFIG_X86_64 | ||
2918 | + insn_init(insn, kaddr, buf_len, 1); | ||
2919 | +#else /* CONFIG_X86_32 */ | ||
2920 | + insn_init(insn, kaddr, buf_len, 0); | ||
2921 | +#endif | ||
2922 | +} | ||
2923 | + | ||
2924 | +static inline int insn_is_avx(struct insn *insn) | ||
2925 | +{ | ||
2926 | + if (!insn->prefixes.got) | ||
2927 | + insn_get_prefixes(insn); | ||
2928 | + return (insn->vex_prefix.value != 0); | ||
2929 | +} | ||
2930 | + | ||
2931 | +static inline int insn_is_evex(struct insn *insn) | ||
2932 | +{ | ||
2933 | + if (!insn->prefixes.got) | ||
2934 | + insn_get_prefixes(insn); | ||
2935 | + return (insn->vex_prefix.nbytes == 4); | ||
2936 | +} | ||
2937 | + | ||
2938 | +/* Ensure this instruction is decoded completely */ | ||
2939 | +static inline int insn_complete(struct insn *insn) | ||
2940 | +{ | ||
2941 | + return insn->opcode.got && insn->modrm.got && insn->sib.got && | ||
2942 | + insn->displacement.got && insn->immediate.got; | ||
2943 | +} | ||
2944 | + | ||
2945 | +static inline insn_byte_t insn_vex_m_bits(struct insn *insn) | ||
2946 | +{ | ||
2947 | + if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ | ||
2948 | + return X86_VEX2_M; | ||
2949 | + else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ | ||
2950 | + return X86_VEX3_M(insn->vex_prefix.bytes[1]); | ||
2951 | + else /* EVEX */ | ||
2952 | + return X86_EVEX_M(insn->vex_prefix.bytes[1]); | ||
2953 | +} | ||
2954 | + | ||
2955 | +static inline insn_byte_t insn_vex_p_bits(struct insn *insn) | ||
2956 | +{ | ||
2957 | + if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ | ||
2958 | + return X86_VEX_P(insn->vex_prefix.bytes[1]); | ||
2959 | + else | ||
2960 | + return X86_VEX_P(insn->vex_prefix.bytes[2]); | ||
2961 | +} | ||
2962 | + | ||
2963 | +/* Get the last prefix id from last prefix or VEX prefix */ | ||
2964 | +static inline int insn_last_prefix_id(struct insn *insn) | ||
2965 | +{ | ||
2966 | + if (insn_is_avx(insn)) | ||
2967 | + return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ | ||
2968 | + | ||
2969 | + if (insn->prefixes.bytes[3]) | ||
2970 | + return inat_get_last_prefix_id(insn->prefixes.bytes[3]); | ||
2971 | + | ||
2972 | + return 0; | ||
2973 | +} | ||
2974 | + | ||
2975 | +/* Offset of each field from kaddr */ | ||
2976 | +static inline int insn_offset_rex_prefix(struct insn *insn) | ||
2977 | +{ | ||
2978 | + return insn->prefixes.nbytes; | ||
2979 | +} | ||
2980 | +static inline int insn_offset_vex_prefix(struct insn *insn) | ||
2981 | +{ | ||
2982 | + return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; | ||
2983 | +} | ||
2984 | +static inline int insn_offset_opcode(struct insn *insn) | ||
2985 | +{ | ||
2986 | + return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; | ||
2987 | +} | ||
2988 | +static inline int insn_offset_modrm(struct insn *insn) | ||
2989 | +{ | ||
2990 | + return insn_offset_opcode(insn) + insn->opcode.nbytes; | ||
2991 | +} | ||
2992 | +static inline int insn_offset_sib(struct insn *insn) | ||
2993 | +{ | ||
2994 | + return insn_offset_modrm(insn) + insn->modrm.nbytes; | ||
2995 | +} | ||
2996 | +static inline int insn_offset_displacement(struct insn *insn) | ||
2997 | +{ | ||
2998 | + return insn_offset_sib(insn) + insn->sib.nbytes; | ||
2999 | +} | ||
3000 | +static inline int insn_offset_immediate(struct insn *insn) | ||
3001 | +{ | ||
3002 | + return insn_offset_displacement(insn) + insn->displacement.nbytes; | ||
3003 | +} | ||
3004 | + | ||
3005 | +#endif /* _ASM_X86_INSN_H */ | ||
3006 | diff --git a/tools/objtool/arch/x86/include/asm/orc_types.h b/tools/objtool/arch/x86/include/asm/orc_types.h | ||
3007 | new file mode 100644 | ||
3008 | index 000000000000..7dc777a6cb40 | ||
3009 | --- /dev/null | ||
3010 | +++ b/tools/objtool/arch/x86/include/asm/orc_types.h | ||
3011 | @@ -0,0 +1,107 @@ | ||
3012 | +/* | ||
3013 | + * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
3014 | + * | ||
3015 | + * This program is free software; you can redistribute it and/or | ||
3016 | + * modify it under the terms of the GNU General Public License | ||
3017 | + * as published by the Free Software Foundation; either version 2 | ||
3018 | + * of the License, or (at your option) any later version. | ||
3019 | + * | ||
3020 | + * This program is distributed in the hope that it will be useful, | ||
3021 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3022 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3023 | + * GNU General Public License for more details. | ||
3024 | + * | ||
3025 | + * You should have received a copy of the GNU General Public License | ||
3026 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
3027 | + */ | ||
3028 | + | ||
3029 | +#ifndef _ORC_TYPES_H | ||
3030 | +#define _ORC_TYPES_H | ||
3031 | + | ||
3032 | +#include <linux/types.h> | ||
3033 | +#include <linux/compiler.h> | ||
3034 | + | ||
3035 | +/* | ||
3036 | + * The ORC_REG_* registers are base registers which are used to find other | ||
3037 | + * registers on the stack. | ||
3038 | + * | ||
3039 | + * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the | ||
3040 | + * address of the previous frame: the caller's SP before it called the current | ||
3041 | + * function. | ||
3042 | + * | ||
3043 | + * ORC_REG_UNDEFINED means the corresponding register's value didn't change in | ||
3044 | + * the current frame. | ||
3045 | + * | ||
3046 | + * The most commonly used base registers are SP and BP -- which the previous SP | ||
3047 | + * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is | ||
3048 | + * usually based on. | ||
3049 | + * | ||
3050 | + * The rest of the base registers are needed for special cases like entry code | ||
3051 | + * and GCC realigned stacks. | ||
3052 | + */ | ||
3053 | +#define ORC_REG_UNDEFINED 0 | ||
3054 | +#define ORC_REG_PREV_SP 1 | ||
3055 | +#define ORC_REG_DX 2 | ||
3056 | +#define ORC_REG_DI 3 | ||
3057 | +#define ORC_REG_BP 4 | ||
3058 | +#define ORC_REG_SP 5 | ||
3059 | +#define ORC_REG_R10 6 | ||
3060 | +#define ORC_REG_R13 7 | ||
3061 | +#define ORC_REG_BP_INDIRECT 8 | ||
3062 | +#define ORC_REG_SP_INDIRECT 9 | ||
3063 | +#define ORC_REG_MAX 15 | ||
3064 | + | ||
3065 | +/* | ||
3066 | + * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the | ||
3067 | + * caller's SP right before it made the call). Used for all callable | ||
3068 | + * functions, i.e. all C code and all callable asm functions. | ||
3069 | + * | ||
3070 | + * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points | ||
3071 | + * to a fully populated pt_regs from a syscall, interrupt, or exception. | ||
3072 | + * | ||
3073 | + * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset | ||
3074 | + * points to the iret return frame. | ||
3075 | + * | ||
3076 | + * The UNWIND_HINT macros are used only for the unwind_hint struct. They | ||
3077 | + * aren't used in struct orc_entry due to size and complexity constraints. | ||
3078 | + * Objtool converts them to real types when it converts the hints to orc | ||
3079 | + * entries. | ||
3080 | + */ | ||
3081 | +#define ORC_TYPE_CALL 0 | ||
3082 | +#define ORC_TYPE_REGS 1 | ||
3083 | +#define ORC_TYPE_REGS_IRET 2 | ||
3084 | +#define UNWIND_HINT_TYPE_SAVE 3 | ||
3085 | +#define UNWIND_HINT_TYPE_RESTORE 4 | ||
3086 | + | ||
3087 | +#ifndef __ASSEMBLY__ | ||
3088 | +/* | ||
3089 | + * This struct is more or less a vastly simplified version of the DWARF Call | ||
3090 | + * Frame Information standard. It contains only the necessary parts of DWARF | ||
3091 | + * CFI, simplified for ease of access by the in-kernel unwinder. It tells the | ||
3092 | + * unwinder how to find the previous SP and BP (and sometimes entry regs) on | ||
3093 | + * the stack for a given code address. Each instance of the struct corresponds | ||
3094 | + * to one or more code locations. | ||
3095 | + */ | ||
3096 | +struct orc_entry { | ||
3097 | + s16 sp_offset; | ||
3098 | + s16 bp_offset; | ||
3099 | + unsigned sp_reg:4; | ||
3100 | + unsigned bp_reg:4; | ||
3101 | + unsigned type:2; | ||
3102 | +}; | ||
3103 | + | ||
3104 | +/* | ||
3105 | + * This struct is used by asm and inline asm code to manually annotate the | ||
3106 | + * location of registers on the stack for the ORC unwinder. | ||
3107 | + * | ||
3108 | + * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. | ||
3109 | + */ | ||
3110 | +struct unwind_hint { | ||
3111 | + u32 ip; | ||
3112 | + s16 sp_offset; | ||
3113 | + u8 sp_reg; | ||
3114 | + u8 type; | ||
3115 | +}; | ||
3116 | +#endif /* __ASSEMBLY__ */ | ||
3117 | + | ||
3118 | +#endif /* _ORC_TYPES_H */ | ||
3119 | diff --git a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk b/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk | ||
3120 | deleted file mode 100644 | ||
3121 | index a3d2c62fd805..000000000000 | ||
3122 | --- a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk | ||
3123 | +++ /dev/null | ||
3124 | @@ -1,392 +0,0 @@ | ||
3125 | -#!/bin/awk -f | ||
3126 | -# gen-insn-attr-x86.awk: Instruction attribute table generator | ||
3127 | -# Written by Masami Hiramatsu <mhiramat@redhat.com> | ||
3128 | -# | ||
3129 | -# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c | ||
3130 | - | ||
3131 | -# Awk implementation sanity check | ||
3132 | -function check_awk_implement() { | ||
3133 | - if (sprintf("%x", 0) != "0") | ||
3134 | - return "Your awk has a printf-format problem." | ||
3135 | - return "" | ||
3136 | -} | ||
3137 | - | ||
3138 | -# Clear working vars | ||
3139 | -function clear_vars() { | ||
3140 | - delete table | ||
3141 | - delete lptable2 | ||
3142 | - delete lptable1 | ||
3143 | - delete lptable3 | ||
3144 | - eid = -1 # escape id | ||
3145 | - gid = -1 # group id | ||
3146 | - aid = -1 # AVX id | ||
3147 | - tname = "" | ||
3148 | -} | ||
3149 | - | ||
3150 | -BEGIN { | ||
3151 | - # Implementation error checking | ||
3152 | - awkchecked = check_awk_implement() | ||
3153 | - if (awkchecked != "") { | ||
3154 | - print "Error: " awkchecked > "/dev/stderr" | ||
3155 | - print "Please try to use gawk." > "/dev/stderr" | ||
3156 | - exit 1 | ||
3157 | - } | ||
3158 | - | ||
3159 | - # Setup generating tables | ||
3160 | - print "/* x86 opcode map generated from x86-opcode-map.txt */" | ||
3161 | - print "/* Do not change this code. */\n" | ||
3162 | - ggid = 1 | ||
3163 | - geid = 1 | ||
3164 | - gaid = 0 | ||
3165 | - delete etable | ||
3166 | - delete gtable | ||
3167 | - delete atable | ||
3168 | - | ||
3169 | - opnd_expr = "^[A-Za-z/]" | ||
3170 | - ext_expr = "^\\(" | ||
3171 | - sep_expr = "^\\|$" | ||
3172 | - group_expr = "^Grp[0-9A-Za-z]+" | ||
3173 | - | ||
3174 | - imm_expr = "^[IJAOL][a-z]" | ||
3175 | - imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" | ||
3176 | - imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" | ||
3177 | - imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" | ||
3178 | - imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" | ||
3179 | - imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" | ||
3180 | - imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" | ||
3181 | - imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" | ||
3182 | - imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" | ||
3183 | - imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" | ||
3184 | - imm_flag["Ob"] = "INAT_MOFFSET" | ||
3185 | - imm_flag["Ov"] = "INAT_MOFFSET" | ||
3186 | - imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" | ||
3187 | - | ||
3188 | - modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" | ||
3189 | - force64_expr = "\\([df]64\\)" | ||
3190 | - rex_expr = "^REX(\\.[XRWB]+)*" | ||
3191 | - fpu_expr = "^ESC" # TODO | ||
3192 | - | ||
3193 | - lprefix1_expr = "\\((66|!F3)\\)" | ||
3194 | - lprefix2_expr = "\\(F3\\)" | ||
3195 | - lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)" | ||
3196 | - lprefix_expr = "\\((66|F2|F3)\\)" | ||
3197 | - max_lprefix = 4 | ||
3198 | - | ||
3199 | - # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript | ||
3200 | - # accepts VEX prefix | ||
3201 | - vexok_opcode_expr = "^[vk].*" | ||
3202 | - vexok_expr = "\\(v1\\)" | ||
3203 | - # All opcodes with (v) superscript supports *only* VEX prefix | ||
3204 | - vexonly_expr = "\\(v\\)" | ||
3205 | - # All opcodes with (ev) superscript supports *only* EVEX prefix | ||
3206 | - evexonly_expr = "\\(ev\\)" | ||
3207 | - | ||
3208 | - prefix_expr = "\\(Prefix\\)" | ||
3209 | - prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" | ||
3210 | - prefix_num["REPNE"] = "INAT_PFX_REPNE" | ||
3211 | - prefix_num["REP/REPE"] = "INAT_PFX_REPE" | ||
3212 | - prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" | ||
3213 | - prefix_num["XRELEASE"] = "INAT_PFX_REPE" | ||
3214 | - prefix_num["LOCK"] = "INAT_PFX_LOCK" | ||
3215 | - prefix_num["SEG=CS"] = "INAT_PFX_CS" | ||
3216 | - prefix_num["SEG=DS"] = "INAT_PFX_DS" | ||
3217 | - prefix_num["SEG=ES"] = "INAT_PFX_ES" | ||
3218 | - prefix_num["SEG=FS"] = "INAT_PFX_FS" | ||
3219 | - prefix_num["SEG=GS"] = "INAT_PFX_GS" | ||
3220 | - prefix_num["SEG=SS"] = "INAT_PFX_SS" | ||
3221 | - prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" | ||
3222 | - prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" | ||
3223 | - prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" | ||
3224 | - prefix_num["EVEX"] = "INAT_PFX_EVEX" | ||
3225 | - | ||
3226 | - clear_vars() | ||
3227 | -} | ||
3228 | - | ||
3229 | -function semantic_error(msg) { | ||
3230 | - print "Semantic error at " NR ": " msg > "/dev/stderr" | ||
3231 | - exit 1 | ||
3232 | -} | ||
3233 | - | ||
3234 | -function debug(msg) { | ||
3235 | - print "DEBUG: " msg | ||
3236 | -} | ||
3237 | - | ||
3238 | -function array_size(arr, i,c) { | ||
3239 | - c = 0 | ||
3240 | - for (i in arr) | ||
3241 | - c++ | ||
3242 | - return c | ||
3243 | -} | ||
3244 | - | ||
3245 | -/^Table:/ { | ||
3246 | - print "/* " $0 " */" | ||
3247 | - if (tname != "") | ||
3248 | - semantic_error("Hit Table: before EndTable:."); | ||
3249 | -} | ||
3250 | - | ||
3251 | -/^Referrer:/ { | ||
3252 | - if (NF != 1) { | ||
3253 | - # escape opcode table | ||
3254 | - ref = "" | ||
3255 | - for (i = 2; i <= NF; i++) | ||
3256 | - ref = ref $i | ||
3257 | - eid = escape[ref] | ||
3258 | - tname = sprintf("inat_escape_table_%d", eid) | ||
3259 | - } | ||
3260 | -} | ||
3261 | - | ||
3262 | -/^AVXcode:/ { | ||
3263 | - if (NF != 1) { | ||
3264 | - # AVX/escape opcode table | ||
3265 | - aid = $2 | ||
3266 | - if (gaid <= aid) | ||
3267 | - gaid = aid + 1 | ||
3268 | - if (tname == "") # AVX only opcode table | ||
3269 | - tname = sprintf("inat_avx_table_%d", $2) | ||
3270 | - } | ||
3271 | - if (aid == -1 && eid == -1) # primary opcode table | ||
3272 | - tname = "inat_primary_table" | ||
3273 | -} | ||
3274 | - | ||
3275 | -/^GrpTable:/ { | ||
3276 | - print "/* " $0 " */" | ||
3277 | - if (!($2 in group)) | ||
3278 | - semantic_error("No group: " $2 ) | ||
3279 | - gid = group[$2] | ||
3280 | - tname = "inat_group_table_" gid | ||
3281 | -} | ||
3282 | - | ||
3283 | -function print_table(tbl,name,fmt,n) | ||
3284 | -{ | ||
3285 | - print "const insn_attr_t " name " = {" | ||
3286 | - for (i = 0; i < n; i++) { | ||
3287 | - id = sprintf(fmt, i) | ||
3288 | - if (tbl[id]) | ||
3289 | - print " [" id "] = " tbl[id] "," | ||
3290 | - } | ||
3291 | - print "};" | ||
3292 | -} | ||
3293 | - | ||
3294 | -/^EndTable/ { | ||
3295 | - if (gid != -1) { | ||
3296 | - # print group tables | ||
3297 | - if (array_size(table) != 0) { | ||
3298 | - print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", | ||
3299 | - "0x%x", 8) | ||
3300 | - gtable[gid,0] = tname | ||
3301 | - } | ||
3302 | - if (array_size(lptable1) != 0) { | ||
3303 | - print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", | ||
3304 | - "0x%x", 8) | ||
3305 | - gtable[gid,1] = tname "_1" | ||
3306 | - } | ||
3307 | - if (array_size(lptable2) != 0) { | ||
3308 | - print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", | ||
3309 | - "0x%x", 8) | ||
3310 | - gtable[gid,2] = tname "_2" | ||
3311 | - } | ||
3312 | - if (array_size(lptable3) != 0) { | ||
3313 | - print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", | ||
3314 | - "0x%x", 8) | ||
3315 | - gtable[gid,3] = tname "_3" | ||
3316 | - } | ||
3317 | - } else { | ||
3318 | - # print primary/escaped tables | ||
3319 | - if (array_size(table) != 0) { | ||
3320 | - print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", | ||
3321 | - "0x%02x", 256) | ||
3322 | - etable[eid,0] = tname | ||
3323 | - if (aid >= 0) | ||
3324 | - atable[aid,0] = tname | ||
3325 | - } | ||
3326 | - if (array_size(lptable1) != 0) { | ||
3327 | - print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", | ||
3328 | - "0x%02x", 256) | ||
3329 | - etable[eid,1] = tname "_1" | ||
3330 | - if (aid >= 0) | ||
3331 | - atable[aid,1] = tname "_1" | ||
3332 | - } | ||
3333 | - if (array_size(lptable2) != 0) { | ||
3334 | - print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", | ||
3335 | - "0x%02x", 256) | ||
3336 | - etable[eid,2] = tname "_2" | ||
3337 | - if (aid >= 0) | ||
3338 | - atable[aid,2] = tname "_2" | ||
3339 | - } | ||
3340 | - if (array_size(lptable3) != 0) { | ||
3341 | - print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", | ||
3342 | - "0x%02x", 256) | ||
3343 | - etable[eid,3] = tname "_3" | ||
3344 | - if (aid >= 0) | ||
3345 | - atable[aid,3] = tname "_3" | ||
3346 | - } | ||
3347 | - } | ||
3348 | - print "" | ||
3349 | - clear_vars() | ||
3350 | -} | ||
3351 | - | ||
3352 | -function add_flags(old,new) { | ||
3353 | - if (old && new) | ||
3354 | - return old " | " new | ||
3355 | - else if (old) | ||
3356 | - return old | ||
3357 | - else | ||
3358 | - return new | ||
3359 | -} | ||
3360 | - | ||
3361 | -# convert operands to flags. | ||
3362 | -function convert_operands(count,opnd, i,j,imm,mod) | ||
3363 | -{ | ||
3364 | - imm = null | ||
3365 | - mod = null | ||
3366 | - for (j = 1; j <= count; j++) { | ||
3367 | - i = opnd[j] | ||
3368 | - if (match(i, imm_expr) == 1) { | ||
3369 | - if (!imm_flag[i]) | ||
3370 | - semantic_error("Unknown imm opnd: " i) | ||
3371 | - if (imm) { | ||
3372 | - if (i != "Ib") | ||
3373 | - semantic_error("Second IMM error") | ||
3374 | - imm = add_flags(imm, "INAT_SCNDIMM") | ||
3375 | - } else | ||
3376 | - imm = imm_flag[i] | ||
3377 | - } else if (match(i, modrm_expr)) | ||
3378 | - mod = "INAT_MODRM" | ||
3379 | - } | ||
3380 | - return add_flags(imm, mod) | ||
3381 | -} | ||
3382 | - | ||
3383 | -/^[0-9a-f]+\:/ { | ||
3384 | - if (NR == 1) | ||
3385 | - next | ||
3386 | - # get index | ||
3387 | - idx = "0x" substr($1, 1, index($1,":") - 1) | ||
3388 | - if (idx in table) | ||
3389 | - semantic_error("Redefine " idx " in " tname) | ||
3390 | - | ||
3391 | - # check if escaped opcode | ||
3392 | - if ("escape" == $2) { | ||
3393 | - if ($3 != "#") | ||
3394 | - semantic_error("No escaped name") | ||
3395 | - ref = "" | ||
3396 | - for (i = 4; i <= NF; i++) | ||
3397 | - ref = ref $i | ||
3398 | - if (ref in escape) | ||
3399 | - semantic_error("Redefine escape (" ref ")") | ||
3400 | - escape[ref] = geid | ||
3401 | - geid++ | ||
3402 | - table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" | ||
3403 | - next | ||
3404 | - } | ||
3405 | - | ||
3406 | - variant = null | ||
3407 | - # converts | ||
3408 | - i = 2 | ||
3409 | - while (i <= NF) { | ||
3410 | - opcode = $(i++) | ||
3411 | - delete opnds | ||
3412 | - ext = null | ||
3413 | - flags = null | ||
3414 | - opnd = null | ||
3415 | - # parse one opcode | ||
3416 | - if (match($i, opnd_expr)) { | ||
3417 | - opnd = $i | ||
3418 | - count = split($(i++), opnds, ",") | ||
3419 | - flags = convert_operands(count, opnds) | ||
3420 | - } | ||
3421 | - if (match($i, ext_expr)) | ||
3422 | - ext = $(i++) | ||
3423 | - if (match($i, sep_expr)) | ||
3424 | - i++ | ||
3425 | - else if (i < NF) | ||
3426 | - semantic_error($i " is not a separator") | ||
3427 | - | ||
3428 | - # check if group opcode | ||
3429 | - if (match(opcode, group_expr)) { | ||
3430 | - if (!(opcode in group)) { | ||
3431 | - group[opcode] = ggid | ||
3432 | - ggid++ | ||
3433 | - } | ||
3434 | - flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") | ||
3435 | - } | ||
3436 | - # check force(or default) 64bit | ||
3437 | - if (match(ext, force64_expr)) | ||
3438 | - flags = add_flags(flags, "INAT_FORCE64") | ||
3439 | - | ||
3440 | - # check REX prefix | ||
3441 | - if (match(opcode, rex_expr)) | ||
3442 | - flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") | ||
3443 | - | ||
3444 | - # check coprocessor escape : TODO | ||
3445 | - if (match(opcode, fpu_expr)) | ||
3446 | - flags = add_flags(flags, "INAT_MODRM") | ||
3447 | - | ||
3448 | - # check VEX codes | ||
3449 | - if (match(ext, evexonly_expr)) | ||
3450 | - flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") | ||
3451 | - else if (match(ext, vexonly_expr)) | ||
3452 | - flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") | ||
3453 | - else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) | ||
3454 | - flags = add_flags(flags, "INAT_VEXOK") | ||
3455 | - | ||
3456 | - # check prefixes | ||
3457 | - if (match(ext, prefix_expr)) { | ||
3458 | - if (!prefix_num[opcode]) | ||
3459 | - semantic_error("Unknown prefix: " opcode) | ||
3460 | - flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") | ||
3461 | - } | ||
3462 | - if (length(flags) == 0) | ||
3463 | - continue | ||
3464 | - # check if last prefix | ||
3465 | - if (match(ext, lprefix1_expr)) { | ||
3466 | - lptable1[idx] = add_flags(lptable1[idx],flags) | ||
3467 | - variant = "INAT_VARIANT" | ||
3468 | - } | ||
3469 | - if (match(ext, lprefix2_expr)) { | ||
3470 | - lptable2[idx] = add_flags(lptable2[idx],flags) | ||
3471 | - variant = "INAT_VARIANT" | ||
3472 | - } | ||
3473 | - if (match(ext, lprefix3_expr)) { | ||
3474 | - lptable3[idx] = add_flags(lptable3[idx],flags) | ||
3475 | - variant = "INAT_VARIANT" | ||
3476 | - } | ||
3477 | - if (!match(ext, lprefix_expr)){ | ||
3478 | - table[idx] = add_flags(table[idx],flags) | ||
3479 | - } | ||
3480 | - } | ||
3481 | - if (variant) | ||
3482 | - table[idx] = add_flags(table[idx],variant) | ||
3483 | -} | ||
3484 | - | ||
3485 | -END { | ||
3486 | - if (awkchecked != "") | ||
3487 | - exit 1 | ||
3488 | - # print escape opcode map's array | ||
3489 | - print "/* Escape opcode map array */" | ||
3490 | - print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ | ||
3491 | - "[INAT_LSTPFX_MAX + 1] = {" | ||
3492 | - for (i = 0; i < geid; i++) | ||
3493 | - for (j = 0; j < max_lprefix; j++) | ||
3494 | - if (etable[i,j]) | ||
3495 | - print " ["i"]["j"] = "etable[i,j]"," | ||
3496 | - print "};\n" | ||
3497 | - # print group opcode map's array | ||
3498 | - print "/* Group opcode map array */" | ||
3499 | - print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ | ||
3500 | - "[INAT_LSTPFX_MAX + 1] = {" | ||
3501 | - for (i = 0; i < ggid; i++) | ||
3502 | - for (j = 0; j < max_lprefix; j++) | ||
3503 | - if (gtable[i,j]) | ||
3504 | - print " ["i"]["j"] = "gtable[i,j]"," | ||
3505 | - print "};\n" | ||
3506 | - # print AVX opcode map's array | ||
3507 | - print "/* AVX opcode map array */" | ||
3508 | - print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ | ||
3509 | - "[INAT_LSTPFX_MAX + 1] = {" | ||
3510 | - for (i = 0; i < gaid; i++) | ||
3511 | - for (j = 0; j < max_lprefix; j++) | ||
3512 | - if (atable[i,j]) | ||
3513 | - print " ["i"]["j"] = "atable[i,j]"," | ||
3514 | - print "};" | ||
3515 | -} | ||
3516 | - | ||
3517 | diff --git a/tools/objtool/arch/x86/insn/inat.c b/tools/objtool/arch/x86/insn/inat.c | ||
3518 | deleted file mode 100644 | ||
3519 | index e4bf28e6f4c7..000000000000 | ||
3520 | --- a/tools/objtool/arch/x86/insn/inat.c | ||
3521 | +++ /dev/null | ||
3522 | @@ -1,97 +0,0 @@ | ||
3523 | -/* | ||
3524 | - * x86 instruction attribute tables | ||
3525 | - * | ||
3526 | - * Written by Masami Hiramatsu <mhiramat@redhat.com> | ||
3527 | - * | ||
3528 | - * This program is free software; you can redistribute it and/or modify | ||
3529 | - * it under the terms of the GNU General Public License as published by | ||
3530 | - * the Free Software Foundation; either version 2 of the License, or | ||
3531 | - * (at your option) any later version. | ||
3532 | - * | ||
3533 | - * This program is distributed in the hope that it will be useful, | ||
3534 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3535 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3536 | - * GNU General Public License for more details. | ||
3537 | - * | ||
3538 | - * You should have received a copy of the GNU General Public License | ||
3539 | - * along with this program; if not, write to the Free Software | ||
3540 | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
3541 | - * | ||
3542 | - */ | ||
3543 | -#include "insn.h" | ||
3544 | - | ||
3545 | -/* Attribute tables are generated from opcode map */ | ||
3546 | -#include "inat-tables.c" | ||
3547 | - | ||
3548 | -/* Attribute search APIs */ | ||
3549 | -insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) | ||
3550 | -{ | ||
3551 | - return inat_primary_table[opcode]; | ||
3552 | -} | ||
3553 | - | ||
3554 | -int inat_get_last_prefix_id(insn_byte_t last_pfx) | ||
3555 | -{ | ||
3556 | - insn_attr_t lpfx_attr; | ||
3557 | - | ||
3558 | - lpfx_attr = inat_get_opcode_attribute(last_pfx); | ||
3559 | - return inat_last_prefix_id(lpfx_attr); | ||
3560 | -} | ||
3561 | - | ||
3562 | -insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, | ||
3563 | - insn_attr_t esc_attr) | ||
3564 | -{ | ||
3565 | - const insn_attr_t *table; | ||
3566 | - int n; | ||
3567 | - | ||
3568 | - n = inat_escape_id(esc_attr); | ||
3569 | - | ||
3570 | - table = inat_escape_tables[n][0]; | ||
3571 | - if (!table) | ||
3572 | - return 0; | ||
3573 | - if (inat_has_variant(table[opcode]) && lpfx_id) { | ||
3574 | - table = inat_escape_tables[n][lpfx_id]; | ||
3575 | - if (!table) | ||
3576 | - return 0; | ||
3577 | - } | ||
3578 | - return table[opcode]; | ||
3579 | -} | ||
3580 | - | ||
3581 | -insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, | ||
3582 | - insn_attr_t grp_attr) | ||
3583 | -{ | ||
3584 | - const insn_attr_t *table; | ||
3585 | - int n; | ||
3586 | - | ||
3587 | - n = inat_group_id(grp_attr); | ||
3588 | - | ||
3589 | - table = inat_group_tables[n][0]; | ||
3590 | - if (!table) | ||
3591 | - return inat_group_common_attribute(grp_attr); | ||
3592 | - if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { | ||
3593 | - table = inat_group_tables[n][lpfx_id]; | ||
3594 | - if (!table) | ||
3595 | - return inat_group_common_attribute(grp_attr); | ||
3596 | - } | ||
3597 | - return table[X86_MODRM_REG(modrm)] | | ||
3598 | - inat_group_common_attribute(grp_attr); | ||
3599 | -} | ||
3600 | - | ||
3601 | -insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, | ||
3602 | - insn_byte_t vex_p) | ||
3603 | -{ | ||
3604 | - const insn_attr_t *table; | ||
3605 | - if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) | ||
3606 | - return 0; | ||
3607 | - /* At first, this checks the master table */ | ||
3608 | - table = inat_avx_tables[vex_m][0]; | ||
3609 | - if (!table) | ||
3610 | - return 0; | ||
3611 | - if (!inat_is_group(table[opcode]) && vex_p) { | ||
3612 | - /* If this is not a group, get attribute directly */ | ||
3613 | - table = inat_avx_tables[vex_m][vex_p]; | ||
3614 | - if (!table) | ||
3615 | - return 0; | ||
3616 | - } | ||
3617 | - return table[opcode]; | ||
3618 | -} | ||
3619 | - | ||
3620 | diff --git a/tools/objtool/arch/x86/insn/inat.h b/tools/objtool/arch/x86/insn/inat.h | ||
3621 | deleted file mode 100644 | ||
3622 | index 125ecd2a300d..000000000000 | ||
3623 | --- a/tools/objtool/arch/x86/insn/inat.h | ||
3624 | +++ /dev/null | ||
3625 | @@ -1,234 +0,0 @@ | ||
3626 | -#ifndef _ASM_X86_INAT_H | ||
3627 | -#define _ASM_X86_INAT_H | ||
3628 | -/* | ||
3629 | - * x86 instruction attributes | ||
3630 | - * | ||
3631 | - * Written by Masami Hiramatsu <mhiramat@redhat.com> | ||
3632 | - * | ||
3633 | - * This program is free software; you can redistribute it and/or modify | ||
3634 | - * it under the terms of the GNU General Public License as published by | ||
3635 | - * the Free Software Foundation; either version 2 of the License, or | ||
3636 | - * (at your option) any later version. | ||
3637 | - * | ||
3638 | - * This program is distributed in the hope that it will be useful, | ||
3639 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3640 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3641 | - * GNU General Public License for more details. | ||
3642 | - * | ||
3643 | - * You should have received a copy of the GNU General Public License | ||
3644 | - * along with this program; if not, write to the Free Software | ||
3645 | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
3646 | - * | ||
3647 | - */ | ||
3648 | -#include "inat_types.h" | ||
3649 | - | ||
3650 | -/* | ||
3651 | - * Internal bits. Don't use bitmasks directly, because these bits are | ||
3652 | - * unstable. You should use checking functions. | ||
3653 | - */ | ||
3654 | - | ||
3655 | -#define INAT_OPCODE_TABLE_SIZE 256 | ||
3656 | -#define INAT_GROUP_TABLE_SIZE 8 | ||
3657 | - | ||
3658 | -/* Legacy last prefixes */ | ||
3659 | -#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ | ||
3660 | -#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ | ||
3661 | -#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ | ||
3662 | -/* Other Legacy prefixes */ | ||
3663 | -#define INAT_PFX_LOCK 4 /* 0xF0 */ | ||
3664 | -#define INAT_PFX_CS 5 /* 0x2E */ | ||
3665 | -#define INAT_PFX_DS 6 /* 0x3E */ | ||
3666 | -#define INAT_PFX_ES 7 /* 0x26 */ | ||
3667 | -#define INAT_PFX_FS 8 /* 0x64 */ | ||
3668 | -#define INAT_PFX_GS 9 /* 0x65 */ | ||
3669 | -#define INAT_PFX_SS 10 /* 0x36 */ | ||
3670 | -#define INAT_PFX_ADDRSZ 11 /* 0x67 */ | ||
3671 | -/* x86-64 REX prefix */ | ||
3672 | -#define INAT_PFX_REX 12 /* 0x4X */ | ||
3673 | -/* AVX VEX prefixes */ | ||
3674 | -#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ | ||
3675 | -#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ | ||
3676 | -#define INAT_PFX_EVEX 15 /* EVEX prefix */ | ||
3677 | - | ||
3678 | -#define INAT_LSTPFX_MAX 3 | ||
3679 | -#define INAT_LGCPFX_MAX 11 | ||
3680 | - | ||
3681 | -/* Immediate size */ | ||
3682 | -#define INAT_IMM_BYTE 1 | ||
3683 | -#define INAT_IMM_WORD 2 | ||
3684 | -#define INAT_IMM_DWORD 3 | ||
3685 | -#define INAT_IMM_QWORD 4 | ||
3686 | -#define INAT_IMM_PTR 5 | ||
3687 | -#define INAT_IMM_VWORD32 6 | ||
3688 | -#define INAT_IMM_VWORD 7 | ||
3689 | - | ||
3690 | -/* Legacy prefix */ | ||
3691 | -#define INAT_PFX_OFFS 0 | ||
3692 | -#define INAT_PFX_BITS 4 | ||
3693 | -#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) | ||
3694 | -#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) | ||
3695 | -/* Escape opcodes */ | ||
3696 | -#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) | ||
3697 | -#define INAT_ESC_BITS 2 | ||
3698 | -#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) | ||
3699 | -#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) | ||
3700 | -/* Group opcodes (1-16) */ | ||
3701 | -#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) | ||
3702 | -#define INAT_GRP_BITS 5 | ||
3703 | -#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) | ||
3704 | -#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) | ||
3705 | -/* Immediates */ | ||
3706 | -#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) | ||
3707 | -#define INAT_IMM_BITS 3 | ||
3708 | -#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) | ||
3709 | -/* Flags */ | ||
3710 | -#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) | ||
3711 | -#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) | ||
3712 | -#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) | ||
3713 | -#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) | ||
3714 | -#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) | ||
3715 | -#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) | ||
3716 | -#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) | ||
3717 | -#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) | ||
3718 | -#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) | ||
3719 | -/* Attribute making macros for attribute tables */ | ||
3720 | -#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) | ||
3721 | -#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) | ||
3722 | -#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) | ||
3723 | -#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) | ||
3724 | - | ||
3725 | -/* Attribute search APIs */ | ||
3726 | -extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); | ||
3727 | -extern int inat_get_last_prefix_id(insn_byte_t last_pfx); | ||
3728 | -extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, | ||
3729 | - int lpfx_id, | ||
3730 | - insn_attr_t esc_attr); | ||
3731 | -extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, | ||
3732 | - int lpfx_id, | ||
3733 | - insn_attr_t esc_attr); | ||
3734 | -extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, | ||
3735 | - insn_byte_t vex_m, | ||
3736 | - insn_byte_t vex_pp); | ||
3737 | - | ||
3738 | -/* Attribute checking functions */ | ||
3739 | -static inline int inat_is_legacy_prefix(insn_attr_t attr) | ||
3740 | -{ | ||
3741 | - attr &= INAT_PFX_MASK; | ||
3742 | - return attr && attr <= INAT_LGCPFX_MAX; | ||
3743 | -} | ||
3744 | - | ||
3745 | -static inline int inat_is_address_size_prefix(insn_attr_t attr) | ||
3746 | -{ | ||
3747 | - return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; | ||
3748 | -} | ||
3749 | - | ||
3750 | -static inline int inat_is_operand_size_prefix(insn_attr_t attr) | ||
3751 | -{ | ||
3752 | - return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; | ||
3753 | -} | ||
3754 | - | ||
3755 | -static inline int inat_is_rex_prefix(insn_attr_t attr) | ||
3756 | -{ | ||
3757 | - return (attr & INAT_PFX_MASK) == INAT_PFX_REX; | ||
3758 | -} | ||
3759 | - | ||
3760 | -static inline int inat_last_prefix_id(insn_attr_t attr) | ||
3761 | -{ | ||
3762 | - if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) | ||
3763 | - return 0; | ||
3764 | - else | ||
3765 | - return attr & INAT_PFX_MASK; | ||
3766 | -} | ||
3767 | - | ||
3768 | -static inline int inat_is_vex_prefix(insn_attr_t attr) | ||
3769 | -{ | ||
3770 | - attr &= INAT_PFX_MASK; | ||
3771 | - return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || | ||
3772 | - attr == INAT_PFX_EVEX; | ||
3773 | -} | ||
3774 | - | ||
3775 | -static inline int inat_is_evex_prefix(insn_attr_t attr) | ||
3776 | -{ | ||
3777 | - return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; | ||
3778 | -} | ||
3779 | - | ||
3780 | -static inline int inat_is_vex3_prefix(insn_attr_t attr) | ||
3781 | -{ | ||
3782 | - return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; | ||
3783 | -} | ||
3784 | - | ||
3785 | -static inline int inat_is_escape(insn_attr_t attr) | ||
3786 | -{ | ||
3787 | - return attr & INAT_ESC_MASK; | ||
3788 | -} | ||
3789 | - | ||
3790 | -static inline int inat_escape_id(insn_attr_t attr) | ||
3791 | -{ | ||
3792 | - return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; | ||
3793 | -} | ||
3794 | - | ||
3795 | -static inline int inat_is_group(insn_attr_t attr) | ||
3796 | -{ | ||
3797 | - return attr & INAT_GRP_MASK; | ||
3798 | -} | ||
3799 | - | ||
3800 | -static inline int inat_group_id(insn_attr_t attr) | ||
3801 | -{ | ||
3802 | - return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; | ||
3803 | -} | ||
3804 | - | ||
3805 | -static inline int inat_group_common_attribute(insn_attr_t attr) | ||
3806 | -{ | ||
3807 | - return attr & ~INAT_GRP_MASK; | ||
3808 | -} | ||
3809 | - | ||
3810 | -static inline int inat_has_immediate(insn_attr_t attr) | ||
3811 | -{ | ||
3812 | - return attr & INAT_IMM_MASK; | ||
3813 | -} | ||
3814 | - | ||
3815 | -static inline int inat_immediate_size(insn_attr_t attr) | ||
3816 | -{ | ||
3817 | - return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; | ||
3818 | -} | ||
3819 | - | ||
3820 | -static inline int inat_has_modrm(insn_attr_t attr) | ||
3821 | -{ | ||
3822 | - return attr & INAT_MODRM; | ||
3823 | -} | ||
3824 | - | ||
3825 | -static inline int inat_is_force64(insn_attr_t attr) | ||
3826 | -{ | ||
3827 | - return attr & INAT_FORCE64; | ||
3828 | -} | ||
3829 | - | ||
3830 | -static inline int inat_has_second_immediate(insn_attr_t attr) | ||
3831 | -{ | ||
3832 | - return attr & INAT_SCNDIMM; | ||
3833 | -} | ||
3834 | - | ||
3835 | -static inline int inat_has_moffset(insn_attr_t attr) | ||
3836 | -{ | ||
3837 | - return attr & INAT_MOFFSET; | ||
3838 | -} | ||
3839 | - | ||
3840 | -static inline int inat_has_variant(insn_attr_t attr) | ||
3841 | -{ | ||
3842 | - return attr & INAT_VARIANT; | ||
3843 | -} | ||
3844 | - | ||
3845 | -static inline int inat_accept_vex(insn_attr_t attr) | ||
3846 | -{ | ||
3847 | - return attr & INAT_VEXOK; | ||
3848 | -} | ||
3849 | - | ||
3850 | -static inline int inat_must_vex(insn_attr_t attr) | ||
3851 | -{ | ||
3852 | - return attr & (INAT_VEXONLY | INAT_EVEXONLY); | ||
3853 | -} | ||
3854 | - | ||
3855 | -static inline int inat_must_evex(insn_attr_t attr) | ||
3856 | -{ | ||
3857 | - return attr & INAT_EVEXONLY; | ||
3858 | -} | ||
3859 | -#endif | ||
3860 | diff --git a/tools/objtool/arch/x86/insn/inat_types.h b/tools/objtool/arch/x86/insn/inat_types.h | ||
3861 | deleted file mode 100644 | ||
3862 | index cb3c20ce39cf..000000000000 | ||
3863 | --- a/tools/objtool/arch/x86/insn/inat_types.h | ||
3864 | +++ /dev/null | ||
3865 | @@ -1,29 +0,0 @@ | ||
3866 | -#ifndef _ASM_X86_INAT_TYPES_H | ||
3867 | -#define _ASM_X86_INAT_TYPES_H | ||
3868 | -/* | ||
3869 | - * x86 instruction attributes | ||
3870 | - * | ||
3871 | - * Written by Masami Hiramatsu <mhiramat@redhat.com> | ||
3872 | - * | ||
3873 | - * This program is free software; you can redistribute it and/or modify | ||
3874 | - * it under the terms of the GNU General Public License as published by | ||
3875 | - * the Free Software Foundation; either version 2 of the License, or | ||
3876 | - * (at your option) any later version. | ||
3877 | - * | ||
3878 | - * This program is distributed in the hope that it will be useful, | ||
3879 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3880 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3881 | - * GNU General Public License for more details. | ||
3882 | - * | ||
3883 | - * You should have received a copy of the GNU General Public License | ||
3884 | - * along with this program; if not, write to the Free Software | ||
3885 | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
3886 | - * | ||
3887 | - */ | ||
3888 | - | ||
3889 | -/* Instruction attributes */ | ||
3890 | -typedef unsigned int insn_attr_t; | ||
3891 | -typedef unsigned char insn_byte_t; | ||
3892 | -typedef signed int insn_value_t; | ||
3893 | - | ||
3894 | -#endif | ||
3895 | diff --git a/tools/objtool/arch/x86/insn/insn.c b/tools/objtool/arch/x86/insn/insn.c | ||
3896 | deleted file mode 100644 | ||
3897 | index ca983e2bea8b..000000000000 | ||
3898 | --- a/tools/objtool/arch/x86/insn/insn.c | ||
3899 | +++ /dev/null | ||
3900 | @@ -1,606 +0,0 @@ | ||
3901 | -/* | ||
3902 | - * x86 instruction analysis | ||
3903 | - * | ||
3904 | - * This program is free software; you can redistribute it and/or modify | ||
3905 | - * it under the terms of the GNU General Public License as published by | ||
3906 | - * the Free Software Foundation; either version 2 of the License, or | ||
3907 | - * (at your option) any later version. | ||
3908 | - * | ||
3909 | - * This program is distributed in the hope that it will be useful, | ||
3910 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3911 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3912 | - * GNU General Public License for more details. | ||
3913 | - * | ||
3914 | - * You should have received a copy of the GNU General Public License | ||
3915 | - * along with this program; if not, write to the Free Software | ||
3916 | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
3917 | - * | ||
3918 | - * Copyright (C) IBM Corporation, 2002, 2004, 2009 | ||
3919 | - */ | ||
3920 | - | ||
3921 | -#ifdef __KERNEL__ | ||
3922 | -#include <linux/string.h> | ||
3923 | -#else | ||
3924 | -#include <string.h> | ||
3925 | -#endif | ||
3926 | -#include "inat.h" | ||
3927 | -#include "insn.h" | ||
3928 | - | ||
3929 | -/* Verify next sizeof(t) bytes can be on the same instruction */ | ||
3930 | -#define validate_next(t, insn, n) \ | ||
3931 | - ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) | ||
3932 | - | ||
3933 | -#define __get_next(t, insn) \ | ||
3934 | - ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) | ||
3935 | - | ||
3936 | -#define __peek_nbyte_next(t, insn, n) \ | ||
3937 | - ({ t r = *(t*)((insn)->next_byte + n); r; }) | ||
3938 | - | ||
3939 | -#define get_next(t, insn) \ | ||
3940 | - ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) | ||
3941 | - | ||
3942 | -#define peek_nbyte_next(t, insn, n) \ | ||
3943 | - ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) | ||
3944 | - | ||
3945 | -#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) | ||
3946 | - | ||
3947 | -/** | ||
3948 | - * insn_init() - initialize struct insn | ||
3949 | - * @insn: &struct insn to be initialized | ||
3950 | - * @kaddr: address (in kernel memory) of instruction (or copy thereof) | ||
3951 | - * @x86_64: !0 for 64-bit kernel or 64-bit app | ||
3952 | - */ | ||
3953 | -void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) | ||
3954 | -{ | ||
3955 | - /* | ||
3956 | - * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid | ||
3957 | - * even if the input buffer is long enough to hold them. | ||
3958 | - */ | ||
3959 | - if (buf_len > MAX_INSN_SIZE) | ||
3960 | - buf_len = MAX_INSN_SIZE; | ||
3961 | - | ||
3962 | - memset(insn, 0, sizeof(*insn)); | ||
3963 | - insn->kaddr = kaddr; | ||
3964 | - insn->end_kaddr = kaddr + buf_len; | ||
3965 | - insn->next_byte = kaddr; | ||
3966 | - insn->x86_64 = x86_64 ? 1 : 0; | ||
3967 | - insn->opnd_bytes = 4; | ||
3968 | - if (x86_64) | ||
3969 | - insn->addr_bytes = 8; | ||
3970 | - else | ||
3971 | - insn->addr_bytes = 4; | ||
3972 | -} | ||
3973 | - | ||
3974 | -/** | ||
3975 | - * insn_get_prefixes - scan x86 instruction prefix bytes | ||
3976 | - * @insn: &struct insn containing instruction | ||
3977 | - * | ||
3978 | - * Populates the @insn->prefixes bitmap, and updates @insn->next_byte | ||
3979 | - * to point to the (first) opcode. No effect if @insn->prefixes.got | ||
3980 | - * is already set. | ||
3981 | - */ | ||
3982 | -void insn_get_prefixes(struct insn *insn) | ||
3983 | -{ | ||
3984 | - struct insn_field *prefixes = &insn->prefixes; | ||
3985 | - insn_attr_t attr; | ||
3986 | - insn_byte_t b, lb; | ||
3987 | - int i, nb; | ||
3988 | - | ||
3989 | - if (prefixes->got) | ||
3990 | - return; | ||
3991 | - | ||
3992 | - nb = 0; | ||
3993 | - lb = 0; | ||
3994 | - b = peek_next(insn_byte_t, insn); | ||
3995 | - attr = inat_get_opcode_attribute(b); | ||
3996 | - while (inat_is_legacy_prefix(attr)) { | ||
3997 | - /* Skip if same prefix */ | ||
3998 | - for (i = 0; i < nb; i++) | ||
3999 | - if (prefixes->bytes[i] == b) | ||
4000 | - goto found; | ||
4001 | - if (nb == 4) | ||
4002 | - /* Invalid instruction */ | ||
4003 | - break; | ||
4004 | - prefixes->bytes[nb++] = b; | ||
4005 | - if (inat_is_address_size_prefix(attr)) { | ||
4006 | - /* address size switches 2/4 or 4/8 */ | ||
4007 | - if (insn->x86_64) | ||
4008 | - insn->addr_bytes ^= 12; | ||
4009 | - else | ||
4010 | - insn->addr_bytes ^= 6; | ||
4011 | - } else if (inat_is_operand_size_prefix(attr)) { | ||
4012 | - /* oprand size switches 2/4 */ | ||
4013 | - insn->opnd_bytes ^= 6; | ||
4014 | - } | ||
4015 | -found: | ||
4016 | - prefixes->nbytes++; | ||
4017 | - insn->next_byte++; | ||
4018 | - lb = b; | ||
4019 | - b = peek_next(insn_byte_t, insn); | ||
4020 | - attr = inat_get_opcode_attribute(b); | ||
4021 | - } | ||
4022 | - /* Set the last prefix */ | ||
4023 | - if (lb && lb != insn->prefixes.bytes[3]) { | ||
4024 | - if (unlikely(insn->prefixes.bytes[3])) { | ||
4025 | - /* Swap the last prefix */ | ||
4026 | - b = insn->prefixes.bytes[3]; | ||
4027 | - for (i = 0; i < nb; i++) | ||
4028 | - if (prefixes->bytes[i] == lb) | ||
4029 | - prefixes->bytes[i] = b; | ||
4030 | - } | ||
4031 | - insn->prefixes.bytes[3] = lb; | ||
4032 | - } | ||
4033 | - | ||
4034 | - /* Decode REX prefix */ | ||
4035 | - if (insn->x86_64) { | ||
4036 | - b = peek_next(insn_byte_t, insn); | ||
4037 | - attr = inat_get_opcode_attribute(b); | ||
4038 | - if (inat_is_rex_prefix(attr)) { | ||
4039 | - insn->rex_prefix.value = b; | ||
4040 | - insn->rex_prefix.nbytes = 1; | ||
4041 | - insn->next_byte++; | ||
4042 | - if (X86_REX_W(b)) | ||
4043 | - /* REX.W overrides opnd_size */ | ||
4044 | - insn->opnd_bytes = 8; | ||
4045 | - } | ||
4046 | - } | ||
4047 | - insn->rex_prefix.got = 1; | ||
4048 | - | ||
4049 | - /* Decode VEX prefix */ | ||
4050 | - b = peek_next(insn_byte_t, insn); | ||
4051 | - attr = inat_get_opcode_attribute(b); | ||
4052 | - if (inat_is_vex_prefix(attr)) { | ||
4053 | - insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); | ||
4054 | - if (!insn->x86_64) { | ||
4055 | - /* | ||
4056 | - * In 32-bits mode, if the [7:6] bits (mod bits of | ||
4057 | - * ModRM) on the second byte are not 11b, it is | ||
4058 | - * LDS or LES or BOUND. | ||
4059 | - */ | ||
4060 | - if (X86_MODRM_MOD(b2) != 3) | ||
4061 | - goto vex_end; | ||
4062 | - } | ||
4063 | - insn->vex_prefix.bytes[0] = b; | ||
4064 | - insn->vex_prefix.bytes[1] = b2; | ||
4065 | - if (inat_is_evex_prefix(attr)) { | ||
4066 | - b2 = peek_nbyte_next(insn_byte_t, insn, 2); | ||
4067 | - insn->vex_prefix.bytes[2] = b2; | ||
4068 | - b2 = peek_nbyte_next(insn_byte_t, insn, 3); | ||
4069 | - insn->vex_prefix.bytes[3] = b2; | ||
4070 | - insn->vex_prefix.nbytes = 4; | ||
4071 | - insn->next_byte += 4; | ||
4072 | - if (insn->x86_64 && X86_VEX_W(b2)) | ||
4073 | - /* VEX.W overrides opnd_size */ | ||
4074 | - insn->opnd_bytes = 8; | ||
4075 | - } else if (inat_is_vex3_prefix(attr)) { | ||
4076 | - b2 = peek_nbyte_next(insn_byte_t, insn, 2); | ||
4077 | - insn->vex_prefix.bytes[2] = b2; | ||
4078 | - insn->vex_prefix.nbytes = 3; | ||
4079 | - insn->next_byte += 3; | ||
4080 | - if (insn->x86_64 && X86_VEX_W(b2)) | ||
4081 | - /* VEX.W overrides opnd_size */ | ||
4082 | - insn->opnd_bytes = 8; | ||
4083 | - } else { | ||
4084 | - /* | ||
4085 | - * For VEX2, fake VEX3-like byte#2. | ||
4086 | - * Makes it easier to decode vex.W, vex.vvvv, | ||
4087 | - * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. | ||
4088 | - */ | ||
4089 | - insn->vex_prefix.bytes[2] = b2 & 0x7f; | ||
4090 | - insn->vex_prefix.nbytes = 2; | ||
4091 | - insn->next_byte += 2; | ||
4092 | - } | ||
4093 | - } | ||
4094 | -vex_end: | ||
4095 | - insn->vex_prefix.got = 1; | ||
4096 | - | ||
4097 | - prefixes->got = 1; | ||
4098 | - | ||
4099 | -err_out: | ||
4100 | - return; | ||
4101 | -} | ||
4102 | - | ||
4103 | -/** | ||
4104 | - * insn_get_opcode - collect opcode(s) | ||
4105 | - * @insn: &struct insn containing instruction | ||
4106 | - * | ||
4107 | - * Populates @insn->opcode, updates @insn->next_byte to point past the | ||
4108 | - * opcode byte(s), and set @insn->attr (except for groups). | ||
4109 | - * If necessary, first collects any preceding (prefix) bytes. | ||
4110 | - * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got | ||
4111 | - * is already 1. | ||
4112 | - */ | ||
4113 | -void insn_get_opcode(struct insn *insn) | ||
4114 | -{ | ||
4115 | - struct insn_field *opcode = &insn->opcode; | ||
4116 | - insn_byte_t op; | ||
4117 | - int pfx_id; | ||
4118 | - if (opcode->got) | ||
4119 | - return; | ||
4120 | - if (!insn->prefixes.got) | ||
4121 | - insn_get_prefixes(insn); | ||
4122 | - | ||
4123 | - /* Get first opcode */ | ||
4124 | - op = get_next(insn_byte_t, insn); | ||
4125 | - opcode->bytes[0] = op; | ||
4126 | - opcode->nbytes = 1; | ||
4127 | - | ||
4128 | - /* Check if there is VEX prefix or not */ | ||
4129 | - if (insn_is_avx(insn)) { | ||
4130 | - insn_byte_t m, p; | ||
4131 | - m = insn_vex_m_bits(insn); | ||
4132 | - p = insn_vex_p_bits(insn); | ||
4133 | - insn->attr = inat_get_avx_attribute(op, m, p); | ||
4134 | - if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || | ||
4135 | - (!inat_accept_vex(insn->attr) && | ||
4136 | - !inat_is_group(insn->attr))) | ||
4137 | - insn->attr = 0; /* This instruction is bad */ | ||
4138 | - goto end; /* VEX has only 1 byte for opcode */ | ||
4139 | - } | ||
4140 | - | ||
4141 | - insn->attr = inat_get_opcode_attribute(op); | ||
4142 | - while (inat_is_escape(insn->attr)) { | ||
4143 | - /* Get escaped opcode */ | ||
4144 | - op = get_next(insn_byte_t, insn); | ||
4145 | - opcode->bytes[opcode->nbytes++] = op; | ||
4146 | - pfx_id = insn_last_prefix_id(insn); | ||
4147 | - insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); | ||
4148 | - } | ||
4149 | - if (inat_must_vex(insn->attr)) | ||
4150 | - insn->attr = 0; /* This instruction is bad */ | ||
4151 | -end: | ||
4152 | - opcode->got = 1; | ||
4153 | - | ||
4154 | -err_out: | ||
4155 | - return; | ||
4156 | -} | ||
4157 | - | ||
4158 | -/** | ||
4159 | - * insn_get_modrm - collect ModRM byte, if any | ||
4160 | - * @insn: &struct insn containing instruction | ||
4161 | - * | ||
4162 | - * Populates @insn->modrm and updates @insn->next_byte to point past the | ||
4163 | - * ModRM byte, if any. If necessary, first collects the preceding bytes | ||
4164 | - * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. | ||
4165 | - */ | ||
4166 | -void insn_get_modrm(struct insn *insn) | ||
4167 | -{ | ||
4168 | - struct insn_field *modrm = &insn->modrm; | ||
4169 | - insn_byte_t pfx_id, mod; | ||
4170 | - if (modrm->got) | ||
4171 | - return; | ||
4172 | - if (!insn->opcode.got) | ||
4173 | - insn_get_opcode(insn); | ||
4174 | - | ||
4175 | - if (inat_has_modrm(insn->attr)) { | ||
4176 | - mod = get_next(insn_byte_t, insn); | ||
4177 | - modrm->value = mod; | ||
4178 | - modrm->nbytes = 1; | ||
4179 | - if (inat_is_group(insn->attr)) { | ||
4180 | - pfx_id = insn_last_prefix_id(insn); | ||
4181 | - insn->attr = inat_get_group_attribute(mod, pfx_id, | ||
4182 | - insn->attr); | ||
4183 | - if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) | ||
4184 | - insn->attr = 0; /* This is bad */ | ||
4185 | - } | ||
4186 | - } | ||
4187 | - | ||
4188 | - if (insn->x86_64 && inat_is_force64(insn->attr)) | ||
4189 | - insn->opnd_bytes = 8; | ||
4190 | - modrm->got = 1; | ||
4191 | - | ||
4192 | -err_out: | ||
4193 | - return; | ||
4194 | -} | ||
4195 | - | ||
4196 | - | ||
4197 | -/** | ||
4198 | - * insn_rip_relative() - Does instruction use RIP-relative addressing mode? | ||
4199 | - * @insn: &struct insn containing instruction | ||
4200 | - * | ||
4201 | - * If necessary, first collects the instruction up to and including the | ||
4202 | - * ModRM byte. No effect if @insn->x86_64 is 0. | ||
4203 | - */ | ||
4204 | -int insn_rip_relative(struct insn *insn) | ||
4205 | -{ | ||
4206 | - struct insn_field *modrm = &insn->modrm; | ||
4207 | - | ||
4208 | - if (!insn->x86_64) | ||
4209 | - return 0; | ||
4210 | - if (!modrm->got) | ||
4211 | - insn_get_modrm(insn); | ||
4212 | - /* | ||
4213 | - * For rip-relative instructions, the mod field (top 2 bits) | ||
4214 | - * is zero and the r/m field (bottom 3 bits) is 0x5. | ||
4215 | - */ | ||
4216 | - return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); | ||
4217 | -} | ||
4218 | - | ||
4219 | -/** | ||
4220 | - * insn_get_sib() - Get the SIB byte of instruction | ||
4221 | - * @insn: &struct insn containing instruction | ||
4222 | - * | ||
4223 | - * If necessary, first collects the instruction up to and including the | ||
4224 | - * ModRM byte. | ||
4225 | - */ | ||
4226 | -void insn_get_sib(struct insn *insn) | ||
4227 | -{ | ||
4228 | - insn_byte_t modrm; | ||
4229 | - | ||
4230 | - if (insn->sib.got) | ||
4231 | - return; | ||
4232 | - if (!insn->modrm.got) | ||
4233 | - insn_get_modrm(insn); | ||
4234 | - if (insn->modrm.nbytes) { | ||
4235 | - modrm = (insn_byte_t)insn->modrm.value; | ||
4236 | - if (insn->addr_bytes != 2 && | ||
4237 | - X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { | ||
4238 | - insn->sib.value = get_next(insn_byte_t, insn); | ||
4239 | - insn->sib.nbytes = 1; | ||
4240 | - } | ||
4241 | - } | ||
4242 | - insn->sib.got = 1; | ||
4243 | - | ||
4244 | -err_out: | ||
4245 | - return; | ||
4246 | -} | ||
4247 | - | ||
4248 | - | ||
4249 | -/** | ||
4250 | - * insn_get_displacement() - Get the displacement of instruction | ||
4251 | - * @insn: &struct insn containing instruction | ||
4252 | - * | ||
4253 | - * If necessary, first collects the instruction up to and including the | ||
4254 | - * SIB byte. | ||
4255 | - * Displacement value is sign-expanded. | ||
4256 | - */ | ||
4257 | -void insn_get_displacement(struct insn *insn) | ||
4258 | -{ | ||
4259 | - insn_byte_t mod, rm, base; | ||
4260 | - | ||
4261 | - if (insn->displacement.got) | ||
4262 | - return; | ||
4263 | - if (!insn->sib.got) | ||
4264 | - insn_get_sib(insn); | ||
4265 | - if (insn->modrm.nbytes) { | ||
4266 | - /* | ||
4267 | - * Interpreting the modrm byte: | ||
4268 | - * mod = 00 - no displacement fields (exceptions below) | ||
4269 | - * mod = 01 - 1-byte displacement field | ||
4270 | - * mod = 10 - displacement field is 4 bytes, or 2 bytes if | ||
4271 | - * address size = 2 (0x67 prefix in 32-bit mode) | ||
4272 | - * mod = 11 - no memory operand | ||
4273 | - * | ||
4274 | - * If address size = 2... | ||
4275 | - * mod = 00, r/m = 110 - displacement field is 2 bytes | ||
4276 | - * | ||
4277 | - * If address size != 2... | ||
4278 | - * mod != 11, r/m = 100 - SIB byte exists | ||
4279 | - * mod = 00, SIB base = 101 - displacement field is 4 bytes | ||
4280 | - * mod = 00, r/m = 101 - rip-relative addressing, displacement | ||
4281 | - * field is 4 bytes | ||
4282 | - */ | ||
4283 | - mod = X86_MODRM_MOD(insn->modrm.value); | ||
4284 | - rm = X86_MODRM_RM(insn->modrm.value); | ||
4285 | - base = X86_SIB_BASE(insn->sib.value); | ||
4286 | - if (mod == 3) | ||
4287 | - goto out; | ||
4288 | - if (mod == 1) { | ||
4289 | - insn->displacement.value = get_next(signed char, insn); | ||
4290 | - insn->displacement.nbytes = 1; | ||
4291 | - } else if (insn->addr_bytes == 2) { | ||
4292 | - if ((mod == 0 && rm == 6) || mod == 2) { | ||
4293 | - insn->displacement.value = | ||
4294 | - get_next(short, insn); | ||
4295 | - insn->displacement.nbytes = 2; | ||
4296 | - } | ||
4297 | - } else { | ||
4298 | - if ((mod == 0 && rm == 5) || mod == 2 || | ||
4299 | - (mod == 0 && base == 5)) { | ||
4300 | - insn->displacement.value = get_next(int, insn); | ||
4301 | - insn->displacement.nbytes = 4; | ||
4302 | - } | ||
4303 | - } | ||
4304 | - } | ||
4305 | -out: | ||
4306 | - insn->displacement.got = 1; | ||
4307 | - | ||
4308 | -err_out: | ||
4309 | - return; | ||
4310 | -} | ||
4311 | - | ||
4312 | -/* Decode moffset16/32/64. Return 0 if failed */ | ||
4313 | -static int __get_moffset(struct insn *insn) | ||
4314 | -{ | ||
4315 | - switch (insn->addr_bytes) { | ||
4316 | - case 2: | ||
4317 | - insn->moffset1.value = get_next(short, insn); | ||
4318 | - insn->moffset1.nbytes = 2; | ||
4319 | - break; | ||
4320 | - case 4: | ||
4321 | - insn->moffset1.value = get_next(int, insn); | ||
4322 | - insn->moffset1.nbytes = 4; | ||
4323 | - break; | ||
4324 | - case 8: | ||
4325 | - insn->moffset1.value = get_next(int, insn); | ||
4326 | - insn->moffset1.nbytes = 4; | ||
4327 | - insn->moffset2.value = get_next(int, insn); | ||
4328 | - insn->moffset2.nbytes = 4; | ||
4329 | - break; | ||
4330 | - default: /* opnd_bytes must be modified manually */ | ||
4331 | - goto err_out; | ||
4332 | - } | ||
4333 | - insn->moffset1.got = insn->moffset2.got = 1; | ||
4334 | - | ||
4335 | - return 1; | ||
4336 | - | ||
4337 | -err_out: | ||
4338 | - return 0; | ||
4339 | -} | ||
4340 | - | ||
4341 | -/* Decode imm v32(Iz). Return 0 if failed */ | ||
4342 | -static int __get_immv32(struct insn *insn) | ||
4343 | -{ | ||
4344 | - switch (insn->opnd_bytes) { | ||
4345 | - case 2: | ||
4346 | - insn->immediate.value = get_next(short, insn); | ||
4347 | - insn->immediate.nbytes = 2; | ||
4348 | - break; | ||
4349 | - case 4: | ||
4350 | - case 8: | ||
4351 | - insn->immediate.value = get_next(int, insn); | ||
4352 | - insn->immediate.nbytes = 4; | ||
4353 | - break; | ||
4354 | - default: /* opnd_bytes must be modified manually */ | ||
4355 | - goto err_out; | ||
4356 | - } | ||
4357 | - | ||
4358 | - return 1; | ||
4359 | - | ||
4360 | -err_out: | ||
4361 | - return 0; | ||
4362 | -} | ||
4363 | - | ||
4364 | -/* Decode imm v64(Iv/Ov), Return 0 if failed */ | ||
4365 | -static int __get_immv(struct insn *insn) | ||
4366 | -{ | ||
4367 | - switch (insn->opnd_bytes) { | ||
4368 | - case 2: | ||
4369 | - insn->immediate1.value = get_next(short, insn); | ||
4370 | - insn->immediate1.nbytes = 2; | ||
4371 | - break; | ||
4372 | - case 4: | ||
4373 | - insn->immediate1.value = get_next(int, insn); | ||
4374 | - insn->immediate1.nbytes = 4; | ||
4375 | - break; | ||
4376 | - case 8: | ||
4377 | - insn->immediate1.value = get_next(int, insn); | ||
4378 | - insn->immediate1.nbytes = 4; | ||
4379 | - insn->immediate2.value = get_next(int, insn); | ||
4380 | - insn->immediate2.nbytes = 4; | ||
4381 | - break; | ||
4382 | - default: /* opnd_bytes must be modified manually */ | ||
4383 | - goto err_out; | ||
4384 | - } | ||
4385 | - insn->immediate1.got = insn->immediate2.got = 1; | ||
4386 | - | ||
4387 | - return 1; | ||
4388 | -err_out: | ||
4389 | - return 0; | ||
4390 | -} | ||
4391 | - | ||
4392 | -/* Decode ptr16:16/32(Ap) */ | ||
4393 | -static int __get_immptr(struct insn *insn) | ||
4394 | -{ | ||
4395 | - switch (insn->opnd_bytes) { | ||
4396 | - case 2: | ||
4397 | - insn->immediate1.value = get_next(short, insn); | ||
4398 | - insn->immediate1.nbytes = 2; | ||
4399 | - break; | ||
4400 | - case 4: | ||
4401 | - insn->immediate1.value = get_next(int, insn); | ||
4402 | - insn->immediate1.nbytes = 4; | ||
4403 | - break; | ||
4404 | - case 8: | ||
4405 | - /* ptr16:64 is not exist (no segment) */ | ||
4406 | - return 0; | ||
4407 | - default: /* opnd_bytes must be modified manually */ | ||
4408 | - goto err_out; | ||
4409 | - } | ||
4410 | - insn->immediate2.value = get_next(unsigned short, insn); | ||
4411 | - insn->immediate2.nbytes = 2; | ||
4412 | - insn->immediate1.got = insn->immediate2.got = 1; | ||
4413 | - | ||
4414 | - return 1; | ||
4415 | -err_out: | ||
4416 | - return 0; | ||
4417 | -} | ||
4418 | - | ||
4419 | -/** | ||
4420 | - * insn_get_immediate() - Get the immediates of instruction | ||
4421 | - * @insn: &struct insn containing instruction | ||
4422 | - * | ||
4423 | - * If necessary, first collects the instruction up to and including the | ||
4424 | - * displacement bytes. | ||
4425 | - * Basically, most of immediates are sign-expanded. Unsigned-value can be | ||
4426 | - * get by bit masking with ((1 << (nbytes * 8)) - 1) | ||
4427 | - */ | ||
4428 | -void insn_get_immediate(struct insn *insn) | ||
4429 | -{ | ||
4430 | - if (insn->immediate.got) | ||
4431 | - return; | ||
4432 | - if (!insn->displacement.got) | ||
4433 | - insn_get_displacement(insn); | ||
4434 | - | ||
4435 | - if (inat_has_moffset(insn->attr)) { | ||
4436 | - if (!__get_moffset(insn)) | ||
4437 | - goto err_out; | ||
4438 | - goto done; | ||
4439 | - } | ||
4440 | - | ||
4441 | - if (!inat_has_immediate(insn->attr)) | ||
4442 | - /* no immediates */ | ||
4443 | - goto done; | ||
4444 | - | ||
4445 | - switch (inat_immediate_size(insn->attr)) { | ||
4446 | - case INAT_IMM_BYTE: | ||
4447 | - insn->immediate.value = get_next(signed char, insn); | ||
4448 | - insn->immediate.nbytes = 1; | ||
4449 | - break; | ||
4450 | - case INAT_IMM_WORD: | ||
4451 | - insn->immediate.value = get_next(short, insn); | ||
4452 | - insn->immediate.nbytes = 2; | ||
4453 | - break; | ||
4454 | - case INAT_IMM_DWORD: | ||
4455 | - insn->immediate.value = get_next(int, insn); | ||
4456 | - insn->immediate.nbytes = 4; | ||
4457 | - break; | ||
4458 | - case INAT_IMM_QWORD: | ||
4459 | - insn->immediate1.value = get_next(int, insn); | ||
4460 | - insn->immediate1.nbytes = 4; | ||
4461 | - insn->immediate2.value = get_next(int, insn); | ||
4462 | - insn->immediate2.nbytes = 4; | ||
4463 | - break; | ||
4464 | - case INAT_IMM_PTR: | ||
4465 | - if (!__get_immptr(insn)) | ||
4466 | - goto err_out; | ||
4467 | - break; | ||
4468 | - case INAT_IMM_VWORD32: | ||
4469 | - if (!__get_immv32(insn)) | ||
4470 | - goto err_out; | ||
4471 | - break; | ||
4472 | - case INAT_IMM_VWORD: | ||
4473 | - if (!__get_immv(insn)) | ||
4474 | - goto err_out; | ||
4475 | - break; | ||
4476 | - default: | ||
4477 | - /* Here, insn must have an immediate, but failed */ | ||
4478 | - goto err_out; | ||
4479 | - } | ||
4480 | - if (inat_has_second_immediate(insn->attr)) { | ||
4481 | - insn->immediate2.value = get_next(signed char, insn); | ||
4482 | - insn->immediate2.nbytes = 1; | ||
4483 | - } | ||
4484 | -done: | ||
4485 | - insn->immediate.got = 1; | ||
4486 | - | ||
4487 | -err_out: | ||
4488 | - return; | ||
4489 | -} | ||
4490 | - | ||
4491 | -/** | ||
4492 | - * insn_get_length() - Get the length of instruction | ||
4493 | - * @insn: &struct insn containing instruction | ||
4494 | - * | ||
4495 | - * If necessary, first collects the instruction up to and including the | ||
4496 | - * immediates bytes. | ||
4497 | - */ | ||
4498 | -void insn_get_length(struct insn *insn) | ||
4499 | -{ | ||
4500 | - if (insn->length) | ||
4501 | - return; | ||
4502 | - if (!insn->immediate.got) | ||
4503 | - insn_get_immediate(insn); | ||
4504 | - insn->length = (unsigned char)((unsigned long)insn->next_byte | ||
4505 | - - (unsigned long)insn->kaddr); | ||
4506 | -} | ||
4507 | diff --git a/tools/objtool/arch/x86/insn/insn.h b/tools/objtool/arch/x86/insn/insn.h | ||
4508 | deleted file mode 100644 | ||
4509 | index e23578c7b1be..000000000000 | ||
4510 | --- a/tools/objtool/arch/x86/insn/insn.h | ||
4511 | +++ /dev/null | ||
4512 | @@ -1,211 +0,0 @@ | ||
4513 | -#ifndef _ASM_X86_INSN_H | ||
4514 | -#define _ASM_X86_INSN_H | ||
4515 | -/* | ||
4516 | - * x86 instruction analysis | ||
4517 | - * | ||
4518 | - * This program is free software; you can redistribute it and/or modify | ||
4519 | - * it under the terms of the GNU General Public License as published by | ||
4520 | - * the Free Software Foundation; either version 2 of the License, or | ||
4521 | - * (at your option) any later version. | ||
4522 | - * | ||
4523 | - * This program is distributed in the hope that it will be useful, | ||
4524 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
4525 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
4526 | - * GNU General Public License for more details. | ||
4527 | - * | ||
4528 | - * You should have received a copy of the GNU General Public License | ||
4529 | - * along with this program; if not, write to the Free Software | ||
4530 | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
4531 | - * | ||
4532 | - * Copyright (C) IBM Corporation, 2009 | ||
4533 | - */ | ||
4534 | - | ||
4535 | -/* insn_attr_t is defined in inat.h */ | ||
4536 | -#include "inat.h" | ||
4537 | - | ||
4538 | -struct insn_field { | ||
4539 | - union { | ||
4540 | - insn_value_t value; | ||
4541 | - insn_byte_t bytes[4]; | ||
4542 | - }; | ||
4543 | - /* !0 if we've run insn_get_xxx() for this field */ | ||
4544 | - unsigned char got; | ||
4545 | - unsigned char nbytes; | ||
4546 | -}; | ||
4547 | - | ||
4548 | -struct insn { | ||
4549 | - struct insn_field prefixes; /* | ||
4550 | - * Prefixes | ||
4551 | - * prefixes.bytes[3]: last prefix | ||
4552 | - */ | ||
4553 | - struct insn_field rex_prefix; /* REX prefix */ | ||
4554 | - struct insn_field vex_prefix; /* VEX prefix */ | ||
4555 | - struct insn_field opcode; /* | ||
4556 | - * opcode.bytes[0]: opcode1 | ||
4557 | - * opcode.bytes[1]: opcode2 | ||
4558 | - * opcode.bytes[2]: opcode3 | ||
4559 | - */ | ||
4560 | - struct insn_field modrm; | ||
4561 | - struct insn_field sib; | ||
4562 | - struct insn_field displacement; | ||
4563 | - union { | ||
4564 | - struct insn_field immediate; | ||
4565 | - struct insn_field moffset1; /* for 64bit MOV */ | ||
4566 | - struct insn_field immediate1; /* for 64bit imm or off16/32 */ | ||
4567 | - }; | ||
4568 | - union { | ||
4569 | - struct insn_field moffset2; /* for 64bit MOV */ | ||
4570 | - struct insn_field immediate2; /* for 64bit imm or seg16 */ | ||
4571 | - }; | ||
4572 | - | ||
4573 | - insn_attr_t attr; | ||
4574 | - unsigned char opnd_bytes; | ||
4575 | - unsigned char addr_bytes; | ||
4576 | - unsigned char length; | ||
4577 | - unsigned char x86_64; | ||
4578 | - | ||
4579 | - const insn_byte_t *kaddr; /* kernel address of insn to analyze */ | ||
4580 | - const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ | ||
4581 | - const insn_byte_t *next_byte; | ||
4582 | -}; | ||
4583 | - | ||
4584 | -#define MAX_INSN_SIZE 15 | ||
4585 | - | ||
4586 | -#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) | ||
4587 | -#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) | ||
4588 | -#define X86_MODRM_RM(modrm) ((modrm) & 0x07) | ||
4589 | - | ||
4590 | -#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) | ||
4591 | -#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) | ||
4592 | -#define X86_SIB_BASE(sib) ((sib) & 0x07) | ||
4593 | - | ||
4594 | -#define X86_REX_W(rex) ((rex) & 8) | ||
4595 | -#define X86_REX_R(rex) ((rex) & 4) | ||
4596 | -#define X86_REX_X(rex) ((rex) & 2) | ||
4597 | -#define X86_REX_B(rex) ((rex) & 1) | ||
4598 | - | ||
4599 | -/* VEX bit flags */ | ||
4600 | -#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ | ||
4601 | -#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ | ||
4602 | -#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ | ||
4603 | -#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ | ||
4604 | -#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ | ||
4605 | -/* VEX bit fields */ | ||
4606 | -#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ | ||
4607 | -#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ | ||
4608 | -#define X86_VEX2_M 1 /* VEX2.M always 1 */ | ||
4609 | -#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ | ||
4610 | -#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ | ||
4611 | -#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ | ||
4612 | - | ||
4613 | -extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); | ||
4614 | -extern void insn_get_prefixes(struct insn *insn); | ||
4615 | -extern void insn_get_opcode(struct insn *insn); | ||
4616 | -extern void insn_get_modrm(struct insn *insn); | ||
4617 | -extern void insn_get_sib(struct insn *insn); | ||
4618 | -extern void insn_get_displacement(struct insn *insn); | ||
4619 | -extern void insn_get_immediate(struct insn *insn); | ||
4620 | -extern void insn_get_length(struct insn *insn); | ||
4621 | - | ||
4622 | -/* Attribute will be determined after getting ModRM (for opcode groups) */ | ||
4623 | -static inline void insn_get_attribute(struct insn *insn) | ||
4624 | -{ | ||
4625 | - insn_get_modrm(insn); | ||
4626 | -} | ||
4627 | - | ||
4628 | -/* Instruction uses RIP-relative addressing */ | ||
4629 | -extern int insn_rip_relative(struct insn *insn); | ||
4630 | - | ||
4631 | -/* Init insn for kernel text */ | ||
4632 | -static inline void kernel_insn_init(struct insn *insn, | ||
4633 | - const void *kaddr, int buf_len) | ||
4634 | -{ | ||
4635 | -#ifdef CONFIG_X86_64 | ||
4636 | - insn_init(insn, kaddr, buf_len, 1); | ||
4637 | -#else /* CONFIG_X86_32 */ | ||
4638 | - insn_init(insn, kaddr, buf_len, 0); | ||
4639 | -#endif | ||
4640 | -} | ||
4641 | - | ||
4642 | -static inline int insn_is_avx(struct insn *insn) | ||
4643 | -{ | ||
4644 | - if (!insn->prefixes.got) | ||
4645 | - insn_get_prefixes(insn); | ||
4646 | - return (insn->vex_prefix.value != 0); | ||
4647 | -} | ||
4648 | - | ||
4649 | -static inline int insn_is_evex(struct insn *insn) | ||
4650 | -{ | ||
4651 | - if (!insn->prefixes.got) | ||
4652 | - insn_get_prefixes(insn); | ||
4653 | - return (insn->vex_prefix.nbytes == 4); | ||
4654 | -} | ||
4655 | - | ||
4656 | -/* Ensure this instruction is decoded completely */ | ||
4657 | -static inline int insn_complete(struct insn *insn) | ||
4658 | -{ | ||
4659 | - return insn->opcode.got && insn->modrm.got && insn->sib.got && | ||
4660 | - insn->displacement.got && insn->immediate.got; | ||
4661 | -} | ||
4662 | - | ||
4663 | -static inline insn_byte_t insn_vex_m_bits(struct insn *insn) | ||
4664 | -{ | ||
4665 | - if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ | ||
4666 | - return X86_VEX2_M; | ||
4667 | - else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ | ||
4668 | - return X86_VEX3_M(insn->vex_prefix.bytes[1]); | ||
4669 | - else /* EVEX */ | ||
4670 | - return X86_EVEX_M(insn->vex_prefix.bytes[1]); | ||
4671 | -} | ||
4672 | - | ||
4673 | -static inline insn_byte_t insn_vex_p_bits(struct insn *insn) | ||
4674 | -{ | ||
4675 | - if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ | ||
4676 | - return X86_VEX_P(insn->vex_prefix.bytes[1]); | ||
4677 | - else | ||
4678 | - return X86_VEX_P(insn->vex_prefix.bytes[2]); | ||
4679 | -} | ||
4680 | - | ||
4681 | -/* Get the last prefix id from last prefix or VEX prefix */ | ||
4682 | -static inline int insn_last_prefix_id(struct insn *insn) | ||
4683 | -{ | ||
4684 | - if (insn_is_avx(insn)) | ||
4685 | - return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ | ||
4686 | - | ||
4687 | - if (insn->prefixes.bytes[3]) | ||
4688 | - return inat_get_last_prefix_id(insn->prefixes.bytes[3]); | ||
4689 | - | ||
4690 | - return 0; | ||
4691 | -} | ||
4692 | - | ||
4693 | -/* Offset of each field from kaddr */ | ||
4694 | -static inline int insn_offset_rex_prefix(struct insn *insn) | ||
4695 | -{ | ||
4696 | - return insn->prefixes.nbytes; | ||
4697 | -} | ||
4698 | -static inline int insn_offset_vex_prefix(struct insn *insn) | ||
4699 | -{ | ||
4700 | - return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; | ||
4701 | -} | ||
4702 | -static inline int insn_offset_opcode(struct insn *insn) | ||
4703 | -{ | ||
4704 | - return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; | ||
4705 | -} | ||
4706 | -static inline int insn_offset_modrm(struct insn *insn) | ||
4707 | -{ | ||
4708 | - return insn_offset_opcode(insn) + insn->opcode.nbytes; | ||
4709 | -} | ||
4710 | -static inline int insn_offset_sib(struct insn *insn) | ||
4711 | -{ | ||
4712 | - return insn_offset_modrm(insn) + insn->modrm.nbytes; | ||
4713 | -} | ||
4714 | -static inline int insn_offset_displacement(struct insn *insn) | ||
4715 | -{ | ||
4716 | - return insn_offset_sib(insn) + insn->sib.nbytes; | ||
4717 | -} | ||
4718 | -static inline int insn_offset_immediate(struct insn *insn) | ||
4719 | -{ | ||
4720 | - return insn_offset_displacement(insn) + insn->displacement.nbytes; | ||
4721 | -} | ||
4722 | - | ||
4723 | -#endif /* _ASM_X86_INSN_H */ | ||
4724 | diff --git a/tools/objtool/arch/x86/insn/x86-opcode-map.txt b/tools/objtool/arch/x86/insn/x86-opcode-map.txt | ||
4725 | deleted file mode 100644 | ||
4726 | index 1754e094bc28..000000000000 | ||
4727 | --- a/tools/objtool/arch/x86/insn/x86-opcode-map.txt | ||
4728 | +++ /dev/null | ||
4729 | @@ -1,1063 +0,0 @@ | ||
4730 | -# x86 Opcode Maps | ||
4731 | -# | ||
4732 | -# This is (mostly) based on following documentations. | ||
4733 | -# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C | ||
4734 | -# (#326018-047US, June 2013) | ||
4735 | -# | ||
4736 | -#<Opcode maps> | ||
4737 | -# Table: table-name | ||
4738 | -# Referrer: escaped-name | ||
4739 | -# AVXcode: avx-code | ||
4740 | -# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] | ||
4741 | -# (or) | ||
4742 | -# opcode: escape # escaped-name | ||
4743 | -# EndTable | ||
4744 | -# | ||
4745 | -# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix | ||
4746 | -# mnemonics that begin with lowercase 'k' accept a VEX prefix | ||
4747 | -# | ||
4748 | -#<group maps> | ||
4749 | -# GrpTable: GrpXXX | ||
4750 | -# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] | ||
4751 | -# EndTable | ||
4752 | -# | ||
4753 | -# AVX Superscripts | ||
4754 | -# (ev): this opcode requires EVEX prefix. | ||
4755 | -# (evo): this opcode is changed by EVEX prefix (EVEX opcode) | ||
4756 | -# (v): this opcode requires VEX prefix. | ||
4757 | -# (v1): this opcode only supports 128bit VEX. | ||
4758 | -# | ||
4759 | -# Last Prefix Superscripts | ||
4760 | -# - (66): the last prefix is 0x66 | ||
4761 | -# - (F3): the last prefix is 0xF3 | ||
4762 | -# - (F2): the last prefix is 0xF2 | ||
4763 | -# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) | ||
4764 | -# - (66&F2): Both 0x66 and 0xF2 prefixes are specified. | ||
4765 | - | ||
4766 | -Table: one byte opcode | ||
4767 | -Referrer: | ||
4768 | -AVXcode: | ||
4769 | -# 0x00 - 0x0f | ||
4770 | -00: ADD Eb,Gb | ||
4771 | -01: ADD Ev,Gv | ||
4772 | -02: ADD Gb,Eb | ||
4773 | -03: ADD Gv,Ev | ||
4774 | -04: ADD AL,Ib | ||
4775 | -05: ADD rAX,Iz | ||
4776 | -06: PUSH ES (i64) | ||
4777 | -07: POP ES (i64) | ||
4778 | -08: OR Eb,Gb | ||
4779 | -09: OR Ev,Gv | ||
4780 | -0a: OR Gb,Eb | ||
4781 | -0b: OR Gv,Ev | ||
4782 | -0c: OR AL,Ib | ||
4783 | -0d: OR rAX,Iz | ||
4784 | -0e: PUSH CS (i64) | ||
4785 | -0f: escape # 2-byte escape | ||
4786 | -# 0x10 - 0x1f | ||
4787 | -10: ADC Eb,Gb | ||
4788 | -11: ADC Ev,Gv | ||
4789 | -12: ADC Gb,Eb | ||
4790 | -13: ADC Gv,Ev | ||
4791 | -14: ADC AL,Ib | ||
4792 | -15: ADC rAX,Iz | ||
4793 | -16: PUSH SS (i64) | ||
4794 | -17: POP SS (i64) | ||
4795 | -18: SBB Eb,Gb | ||
4796 | -19: SBB Ev,Gv | ||
4797 | -1a: SBB Gb,Eb | ||
4798 | -1b: SBB Gv,Ev | ||
4799 | -1c: SBB AL,Ib | ||
4800 | -1d: SBB rAX,Iz | ||
4801 | -1e: PUSH DS (i64) | ||
4802 | -1f: POP DS (i64) | ||
4803 | -# 0x20 - 0x2f | ||
4804 | -20: AND Eb,Gb | ||
4805 | -21: AND Ev,Gv | ||
4806 | -22: AND Gb,Eb | ||
4807 | -23: AND Gv,Ev | ||
4808 | -24: AND AL,Ib | ||
4809 | -25: AND rAx,Iz | ||
4810 | -26: SEG=ES (Prefix) | ||
4811 | -27: DAA (i64) | ||
4812 | -28: SUB Eb,Gb | ||
4813 | -29: SUB Ev,Gv | ||
4814 | -2a: SUB Gb,Eb | ||
4815 | -2b: SUB Gv,Ev | ||
4816 | -2c: SUB AL,Ib | ||
4817 | -2d: SUB rAX,Iz | ||
4818 | -2e: SEG=CS (Prefix) | ||
4819 | -2f: DAS (i64) | ||
4820 | -# 0x30 - 0x3f | ||
4821 | -30: XOR Eb,Gb | ||
4822 | -31: XOR Ev,Gv | ||
4823 | -32: XOR Gb,Eb | ||
4824 | -33: XOR Gv,Ev | ||
4825 | -34: XOR AL,Ib | ||
4826 | -35: XOR rAX,Iz | ||
4827 | -36: SEG=SS (Prefix) | ||
4828 | -37: AAA (i64) | ||
4829 | -38: CMP Eb,Gb | ||
4830 | -39: CMP Ev,Gv | ||
4831 | -3a: CMP Gb,Eb | ||
4832 | -3b: CMP Gv,Ev | ||
4833 | -3c: CMP AL,Ib | ||
4834 | -3d: CMP rAX,Iz | ||
4835 | -3e: SEG=DS (Prefix) | ||
4836 | -3f: AAS (i64) | ||
4837 | -# 0x40 - 0x4f | ||
4838 | -40: INC eAX (i64) | REX (o64) | ||
4839 | -41: INC eCX (i64) | REX.B (o64) | ||
4840 | -42: INC eDX (i64) | REX.X (o64) | ||
4841 | -43: INC eBX (i64) | REX.XB (o64) | ||
4842 | -44: INC eSP (i64) | REX.R (o64) | ||
4843 | -45: INC eBP (i64) | REX.RB (o64) | ||
4844 | -46: INC eSI (i64) | REX.RX (o64) | ||
4845 | -47: INC eDI (i64) | REX.RXB (o64) | ||
4846 | -48: DEC eAX (i64) | REX.W (o64) | ||
4847 | -49: DEC eCX (i64) | REX.WB (o64) | ||
4848 | -4a: DEC eDX (i64) | REX.WX (o64) | ||
4849 | -4b: DEC eBX (i64) | REX.WXB (o64) | ||
4850 | -4c: DEC eSP (i64) | REX.WR (o64) | ||
4851 | -4d: DEC eBP (i64) | REX.WRB (o64) | ||
4852 | -4e: DEC eSI (i64) | REX.WRX (o64) | ||
4853 | -4f: DEC eDI (i64) | REX.WRXB (o64) | ||
4854 | -# 0x50 - 0x5f | ||
4855 | -50: PUSH rAX/r8 (d64) | ||
4856 | -51: PUSH rCX/r9 (d64) | ||
4857 | -52: PUSH rDX/r10 (d64) | ||
4858 | -53: PUSH rBX/r11 (d64) | ||
4859 | -54: PUSH rSP/r12 (d64) | ||
4860 | -55: PUSH rBP/r13 (d64) | ||
4861 | -56: PUSH rSI/r14 (d64) | ||
4862 | -57: PUSH rDI/r15 (d64) | ||
4863 | -58: POP rAX/r8 (d64) | ||
4864 | -59: POP rCX/r9 (d64) | ||
4865 | -5a: POP rDX/r10 (d64) | ||
4866 | -5b: POP rBX/r11 (d64) | ||
4867 | -5c: POP rSP/r12 (d64) | ||
4868 | -5d: POP rBP/r13 (d64) | ||
4869 | -5e: POP rSI/r14 (d64) | ||
4870 | -5f: POP rDI/r15 (d64) | ||
4871 | -# 0x60 - 0x6f | ||
4872 | -60: PUSHA/PUSHAD (i64) | ||
4873 | -61: POPA/POPAD (i64) | ||
4874 | -62: BOUND Gv,Ma (i64) | EVEX (Prefix) | ||
4875 | -63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) | ||
4876 | -64: SEG=FS (Prefix) | ||
4877 | -65: SEG=GS (Prefix) | ||
4878 | -66: Operand-Size (Prefix) | ||
4879 | -67: Address-Size (Prefix) | ||
4880 | -68: PUSH Iz (d64) | ||
4881 | -69: IMUL Gv,Ev,Iz | ||
4882 | -6a: PUSH Ib (d64) | ||
4883 | -6b: IMUL Gv,Ev,Ib | ||
4884 | -6c: INS/INSB Yb,DX | ||
4885 | -6d: INS/INSW/INSD Yz,DX | ||
4886 | -6e: OUTS/OUTSB DX,Xb | ||
4887 | -6f: OUTS/OUTSW/OUTSD DX,Xz | ||
4888 | -# 0x70 - 0x7f | ||
4889 | -70: JO Jb | ||
4890 | -71: JNO Jb | ||
4891 | -72: JB/JNAE/JC Jb | ||
4892 | -73: JNB/JAE/JNC Jb | ||
4893 | -74: JZ/JE Jb | ||
4894 | -75: JNZ/JNE Jb | ||
4895 | -76: JBE/JNA Jb | ||
4896 | -77: JNBE/JA Jb | ||
4897 | -78: JS Jb | ||
4898 | -79: JNS Jb | ||
4899 | -7a: JP/JPE Jb | ||
4900 | -7b: JNP/JPO Jb | ||
4901 | -7c: JL/JNGE Jb | ||
4902 | -7d: JNL/JGE Jb | ||
4903 | -7e: JLE/JNG Jb | ||
4904 | -7f: JNLE/JG Jb | ||
4905 | -# 0x80 - 0x8f | ||
4906 | -80: Grp1 Eb,Ib (1A) | ||
4907 | -81: Grp1 Ev,Iz (1A) | ||
4908 | -82: Grp1 Eb,Ib (1A),(i64) | ||
4909 | -83: Grp1 Ev,Ib (1A) | ||
4910 | -84: TEST Eb,Gb | ||
4911 | -85: TEST Ev,Gv | ||
4912 | -86: XCHG Eb,Gb | ||
4913 | -87: XCHG Ev,Gv | ||
4914 | -88: MOV Eb,Gb | ||
4915 | -89: MOV Ev,Gv | ||
4916 | -8a: MOV Gb,Eb | ||
4917 | -8b: MOV Gv,Ev | ||
4918 | -8c: MOV Ev,Sw | ||
4919 | -8d: LEA Gv,M | ||
4920 | -8e: MOV Sw,Ew | ||
4921 | -8f: Grp1A (1A) | POP Ev (d64) | ||
4922 | -# 0x90 - 0x9f | ||
4923 | -90: NOP | PAUSE (F3) | XCHG r8,rAX | ||
4924 | -91: XCHG rCX/r9,rAX | ||
4925 | -92: XCHG rDX/r10,rAX | ||
4926 | -93: XCHG rBX/r11,rAX | ||
4927 | -94: XCHG rSP/r12,rAX | ||
4928 | -95: XCHG rBP/r13,rAX | ||
4929 | -96: XCHG rSI/r14,rAX | ||
4930 | -97: XCHG rDI/r15,rAX | ||
4931 | -98: CBW/CWDE/CDQE | ||
4932 | -99: CWD/CDQ/CQO | ||
4933 | -9a: CALLF Ap (i64) | ||
4934 | -9b: FWAIT/WAIT | ||
4935 | -9c: PUSHF/D/Q Fv (d64) | ||
4936 | -9d: POPF/D/Q Fv (d64) | ||
4937 | -9e: SAHF | ||
4938 | -9f: LAHF | ||
4939 | -# 0xa0 - 0xaf | ||
4940 | -a0: MOV AL,Ob | ||
4941 | -a1: MOV rAX,Ov | ||
4942 | -a2: MOV Ob,AL | ||
4943 | -a3: MOV Ov,rAX | ||
4944 | -a4: MOVS/B Yb,Xb | ||
4945 | -a5: MOVS/W/D/Q Yv,Xv | ||
4946 | -a6: CMPS/B Xb,Yb | ||
4947 | -a7: CMPS/W/D Xv,Yv | ||
4948 | -a8: TEST AL,Ib | ||
4949 | -a9: TEST rAX,Iz | ||
4950 | -aa: STOS/B Yb,AL | ||
4951 | -ab: STOS/W/D/Q Yv,rAX | ||
4952 | -ac: LODS/B AL,Xb | ||
4953 | -ad: LODS/W/D/Q rAX,Xv | ||
4954 | -ae: SCAS/B AL,Yb | ||
4955 | -# Note: The May 2011 Intel manual shows Xv for the second parameter of the | ||
4956 | -# next instruction but Yv is correct | ||
4957 | -af: SCAS/W/D/Q rAX,Yv | ||
4958 | -# 0xb0 - 0xbf | ||
4959 | -b0: MOV AL/R8L,Ib | ||
4960 | -b1: MOV CL/R9L,Ib | ||
4961 | -b2: MOV DL/R10L,Ib | ||
4962 | -b3: MOV BL/R11L,Ib | ||
4963 | -b4: MOV AH/R12L,Ib | ||
4964 | -b5: MOV CH/R13L,Ib | ||
4965 | -b6: MOV DH/R14L,Ib | ||
4966 | -b7: MOV BH/R15L,Ib | ||
4967 | -b8: MOV rAX/r8,Iv | ||
4968 | -b9: MOV rCX/r9,Iv | ||
4969 | -ba: MOV rDX/r10,Iv | ||
4970 | -bb: MOV rBX/r11,Iv | ||
4971 | -bc: MOV rSP/r12,Iv | ||
4972 | -bd: MOV rBP/r13,Iv | ||
4973 | -be: MOV rSI/r14,Iv | ||
4974 | -bf: MOV rDI/r15,Iv | ||
4975 | -# 0xc0 - 0xcf | ||
4976 | -c0: Grp2 Eb,Ib (1A) | ||
4977 | -c1: Grp2 Ev,Ib (1A) | ||
4978 | -c2: RETN Iw (f64) | ||
4979 | -c3: RETN | ||
4980 | -c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) | ||
4981 | -c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) | ||
4982 | -c6: Grp11A Eb,Ib (1A) | ||
4983 | -c7: Grp11B Ev,Iz (1A) | ||
4984 | -c8: ENTER Iw,Ib | ||
4985 | -c9: LEAVE (d64) | ||
4986 | -ca: RETF Iw | ||
4987 | -cb: RETF | ||
4988 | -cc: INT3 | ||
4989 | -cd: INT Ib | ||
4990 | -ce: INTO (i64) | ||
4991 | -cf: IRET/D/Q | ||
4992 | -# 0xd0 - 0xdf | ||
4993 | -d0: Grp2 Eb,1 (1A) | ||
4994 | -d1: Grp2 Ev,1 (1A) | ||
4995 | -d2: Grp2 Eb,CL (1A) | ||
4996 | -d3: Grp2 Ev,CL (1A) | ||
4997 | -d4: AAM Ib (i64) | ||
4998 | -d5: AAD Ib (i64) | ||
4999 | -d6: | ||
5000 | -d7: XLAT/XLATB | ||
5001 | -d8: ESC | ||
5002 | -d9: ESC | ||
5003 | -da: ESC | ||
5004 | -db: ESC | ||
5005 | -dc: ESC | ||
5006 | -dd: ESC | ||
5007 | -de: ESC | ||
5008 | -df: ESC | ||
5009 | -# 0xe0 - 0xef | ||
5010 | -# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix | ||
5011 | -# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation | ||
5012 | -# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD. | ||
5013 | -e0: LOOPNE/LOOPNZ Jb (f64) | ||
5014 | -e1: LOOPE/LOOPZ Jb (f64) | ||
5015 | -e2: LOOP Jb (f64) | ||
5016 | -e3: JrCXZ Jb (f64) | ||
5017 | -e4: IN AL,Ib | ||
5018 | -e5: IN eAX,Ib | ||
5019 | -e6: OUT Ib,AL | ||
5020 | -e7: OUT Ib,eAX | ||
5021 | -# With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset | ||
5022 | -# in "near" jumps and calls is 16-bit. For CALL, | ||
5023 | -# push of return address is 16-bit wide, RSP is decremented by 2 | ||
5024 | -# but is not truncated to 16 bits, unlike RIP. | ||
5025 | -e8: CALL Jz (f64) | ||
5026 | -e9: JMP-near Jz (f64) | ||
5027 | -ea: JMP-far Ap (i64) | ||
5028 | -eb: JMP-short Jb (f64) | ||
5029 | -ec: IN AL,DX | ||
5030 | -ed: IN eAX,DX | ||
5031 | -ee: OUT DX,AL | ||
5032 | -ef: OUT DX,eAX | ||
5033 | -# 0xf0 - 0xff | ||
5034 | -f0: LOCK (Prefix) | ||
5035 | -f1: | ||
5036 | -f2: REPNE (Prefix) | XACQUIRE (Prefix) | ||
5037 | -f3: REP/REPE (Prefix) | XRELEASE (Prefix) | ||
5038 | -f4: HLT | ||
5039 | -f5: CMC | ||
5040 | -f6: Grp3_1 Eb (1A) | ||
5041 | -f7: Grp3_2 Ev (1A) | ||
5042 | -f8: CLC | ||
5043 | -f9: STC | ||
5044 | -fa: CLI | ||
5045 | -fb: STI | ||
5046 | -fc: CLD | ||
5047 | -fd: STD | ||
5048 | -fe: Grp4 (1A) | ||
5049 | -ff: Grp5 (1A) | ||
5050 | -EndTable | ||
5051 | - | ||
5052 | -Table: 2-byte opcode (0x0f) | ||
5053 | -Referrer: 2-byte escape | ||
5054 | -AVXcode: 1 | ||
5055 | -# 0x0f 0x00-0x0f | ||
5056 | -00: Grp6 (1A) | ||
5057 | -01: Grp7 (1A) | ||
5058 | -02: LAR Gv,Ew | ||
5059 | -03: LSL Gv,Ew | ||
5060 | -04: | ||
5061 | -05: SYSCALL (o64) | ||
5062 | -06: CLTS | ||
5063 | -07: SYSRET (o64) | ||
5064 | -08: INVD | ||
5065 | -09: WBINVD | ||
5066 | -0a: | ||
5067 | -0b: UD2 (1B) | ||
5068 | -0c: | ||
5069 | -# AMD's prefetch group. Intel supports prefetchw(/1) only. | ||
5070 | -0d: GrpP | ||
5071 | -0e: FEMMS | ||
5072 | -# 3DNow! uses the last imm byte as opcode extension. | ||
5073 | -0f: 3DNow! Pq,Qq,Ib | ||
5074 | -# 0x0f 0x10-0x1f | ||
5075 | -# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands | ||
5076 | -# but it actually has operands. And also, vmovss and vmovsd only accept 128bit. | ||
5077 | -# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. | ||
5078 | -# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming | ||
5079 | -# Reference A.1 | ||
5080 | -10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) | ||
5081 | -11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) | ||
5082 | -12: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2) | ||
5083 | -13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) | ||
5084 | -14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) | ||
5085 | -15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) | ||
5086 | -16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) | ||
5087 | -17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) | ||
5088 | -18: Grp16 (1A) | ||
5089 | -19: | ||
5090 | -# Intel SDM opcode map does not list MPX instructions. For now using Gv for | ||
5091 | -# bnd registers and Ev for everything else is OK because the instruction | ||
5092 | -# decoder does not use the information except as an indication that there is | ||
5093 | -# a ModR/M byte. | ||
5094 | -1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev | ||
5095 | -1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv | ||
5096 | -1c: | ||
5097 | -1d: | ||
5098 | -1e: | ||
5099 | -1f: NOP Ev | ||
5100 | -# 0x0f 0x20-0x2f | ||
5101 | -20: MOV Rd,Cd | ||
5102 | -21: MOV Rd,Dd | ||
5103 | -22: MOV Cd,Rd | ||
5104 | -23: MOV Dd,Rd | ||
5105 | -24: | ||
5106 | -25: | ||
5107 | -26: | ||
5108 | -27: | ||
5109 | -28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) | ||
5110 | -29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) | ||
5111 | -2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) | ||
5112 | -2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) | ||
5113 | -2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) | ||
5114 | -2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) | ||
5115 | -2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) | ||
5116 | -2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) | ||
5117 | -# 0x0f 0x30-0x3f | ||
5118 | -30: WRMSR | ||
5119 | -31: RDTSC | ||
5120 | -32: RDMSR | ||
5121 | -33: RDPMC | ||
5122 | -34: SYSENTER | ||
5123 | -35: SYSEXIT | ||
5124 | -36: | ||
5125 | -37: GETSEC | ||
5126 | -38: escape # 3-byte escape 1 | ||
5127 | -39: | ||
5128 | -3a: escape # 3-byte escape 2 | ||
5129 | -3b: | ||
5130 | -3c: | ||
5131 | -3d: | ||
5132 | -3e: | ||
5133 | -3f: | ||
5134 | -# 0x0f 0x40-0x4f | ||
5135 | -40: CMOVO Gv,Ev | ||
5136 | -41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) | ||
5137 | -42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) | ||
5138 | -43: CMOVAE/NB/NC Gv,Ev | ||
5139 | -44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) | ||
5140 | -45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) | ||
5141 | -46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) | ||
5142 | -47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) | ||
5143 | -48: CMOVS Gv,Ev | ||
5144 | -49: CMOVNS Gv,Ev | ||
5145 | -4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) | ||
5146 | -4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk | ||
5147 | -4c: CMOVL/NGE Gv,Ev | ||
5148 | -4d: CMOVNL/GE Gv,Ev | ||
5149 | -4e: CMOVLE/NG Gv,Ev | ||
5150 | -4f: CMOVNLE/G Gv,Ev | ||
5151 | -# 0x0f 0x50-0x5f | ||
5152 | -50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) | ||
5153 | -51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) | ||
5154 | -52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) | ||
5155 | -53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) | ||
5156 | -54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) | ||
5157 | -55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) | ||
5158 | -56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) | ||
5159 | -57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) | ||
5160 | -58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) | ||
5161 | -59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) | ||
5162 | -5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) | ||
5163 | -5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) | ||
5164 | -5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) | ||
5165 | -5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) | ||
5166 | -5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) | ||
5167 | -5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) | ||
5168 | -# 0x0f 0x60-0x6f | ||
5169 | -60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) | ||
5170 | -61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) | ||
5171 | -62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) | ||
5172 | -63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) | ||
5173 | -64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) | ||
5174 | -65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) | ||
5175 | -66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) | ||
5176 | -67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) | ||
5177 | -68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) | ||
5178 | -69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) | ||
5179 | -6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) | ||
5180 | -6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) | ||
5181 | -6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) | ||
5182 | -6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) | ||
5183 | -6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) | ||
5184 | -6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqa32/64 Vx,Wx (66),(evo) | vmovdqu Vx,Wx (F3) | vmovdqu32/64 Vx,Wx (F3),(evo) | vmovdqu8/16 Vx,Wx (F2),(ev) | ||
5185 | -# 0x0f 0x70-0x7f | ||
5186 | -70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) | ||
5187 | -71: Grp12 (1A) | ||
5188 | -72: Grp13 (1A) | ||
5189 | -73: Grp14 (1A) | ||
5190 | -74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) | ||
5191 | -75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) | ||
5192 | -76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) | ||
5193 | -# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. | ||
5194 | -77: emms | vzeroupper | vzeroall | ||
5195 | -78: VMREAD Ey,Gy | vcvttps2udq/pd2udq Vx,Wpd (evo) | vcvttsd2usi Gv,Wx (F2),(ev) | vcvttss2usi Gv,Wx (F3),(ev) | vcvttps2uqq/pd2uqq Vx,Wx (66),(ev) | ||
5196 | -79: VMWRITE Gy,Ey | vcvtps2udq/pd2udq Vx,Wpd (evo) | vcvtsd2usi Gv,Wx (F2),(ev) | vcvtss2usi Gv,Wx (F3),(ev) | vcvtps2uqq/pd2uqq Vx,Wx (66),(ev) | ||
5197 | -7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) | ||
5198 | -7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) | ||
5199 | -7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) | ||
5200 | -7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) | ||
5201 | -7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) | ||
5202 | -7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev) | ||
5203 | -# 0x0f 0x80-0x8f | ||
5204 | -# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). | ||
5205 | -80: JO Jz (f64) | ||
5206 | -81: JNO Jz (f64) | ||
5207 | -82: JB/JC/JNAE Jz (f64) | ||
5208 | -83: JAE/JNB/JNC Jz (f64) | ||
5209 | -84: JE/JZ Jz (f64) | ||
5210 | -85: JNE/JNZ Jz (f64) | ||
5211 | -86: JBE/JNA Jz (f64) | ||
5212 | -87: JA/JNBE Jz (f64) | ||
5213 | -88: JS Jz (f64) | ||
5214 | -89: JNS Jz (f64) | ||
5215 | -8a: JP/JPE Jz (f64) | ||
5216 | -8b: JNP/JPO Jz (f64) | ||
5217 | -8c: JL/JNGE Jz (f64) | ||
5218 | -8d: JNL/JGE Jz (f64) | ||
5219 | -8e: JLE/JNG Jz (f64) | ||
5220 | -8f: JNLE/JG Jz (f64) | ||
5221 | -# 0x0f 0x90-0x9f | ||
5222 | -90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) | ||
5223 | -91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) | ||
5224 | -92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) | ||
5225 | -93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) | ||
5226 | -94: SETE/Z Eb | ||
5227 | -95: SETNE/NZ Eb | ||
5228 | -96: SETBE/NA Eb | ||
5229 | -97: SETA/NBE Eb | ||
5230 | -98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) | ||
5231 | -99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) | ||
5232 | -9a: SETP/PE Eb | ||
5233 | -9b: SETNP/PO Eb | ||
5234 | -9c: SETL/NGE Eb | ||
5235 | -9d: SETNL/GE Eb | ||
5236 | -9e: SETLE/NG Eb | ||
5237 | -9f: SETNLE/G Eb | ||
5238 | -# 0x0f 0xa0-0xaf | ||
5239 | -a0: PUSH FS (d64) | ||
5240 | -a1: POP FS (d64) | ||
5241 | -a2: CPUID | ||
5242 | -a3: BT Ev,Gv | ||
5243 | -a4: SHLD Ev,Gv,Ib | ||
5244 | -a5: SHLD Ev,Gv,CL | ||
5245 | -a6: GrpPDLK | ||
5246 | -a7: GrpRNG | ||
5247 | -a8: PUSH GS (d64) | ||
5248 | -a9: POP GS (d64) | ||
5249 | -aa: RSM | ||
5250 | -ab: BTS Ev,Gv | ||
5251 | -ac: SHRD Ev,Gv,Ib | ||
5252 | -ad: SHRD Ev,Gv,CL | ||
5253 | -ae: Grp15 (1A),(1C) | ||
5254 | -af: IMUL Gv,Ev | ||
5255 | -# 0x0f 0xb0-0xbf | ||
5256 | -b0: CMPXCHG Eb,Gb | ||
5257 | -b1: CMPXCHG Ev,Gv | ||
5258 | -b2: LSS Gv,Mp | ||
5259 | -b3: BTR Ev,Gv | ||
5260 | -b4: LFS Gv,Mp | ||
5261 | -b5: LGS Gv,Mp | ||
5262 | -b6: MOVZX Gv,Eb | ||
5263 | -b7: MOVZX Gv,Ew | ||
5264 | -b8: JMPE (!F3) | POPCNT Gv,Ev (F3) | ||
5265 | -b9: Grp10 (1A) | ||
5266 | -ba: Grp8 Ev,Ib (1A) | ||
5267 | -bb: BTC Ev,Gv | ||
5268 | -bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) | ||
5269 | -bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) | ||
5270 | -be: MOVSX Gv,Eb | ||
5271 | -bf: MOVSX Gv,Ew | ||
5272 | -# 0x0f 0xc0-0xcf | ||
5273 | -c0: XADD Eb,Gb | ||
5274 | -c1: XADD Ev,Gv | ||
5275 | -c2: vcmpps Vps,Hps,Wps,Ib | vcmppd Vpd,Hpd,Wpd,Ib (66) | vcmpss Vss,Hss,Wss,Ib (F3),(v1) | vcmpsd Vsd,Hsd,Wsd,Ib (F2),(v1) | ||
5276 | -c3: movnti My,Gy | ||
5277 | -c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) | ||
5278 | -c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) | ||
5279 | -c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) | ||
5280 | -c7: Grp9 (1A) | ||
5281 | -c8: BSWAP RAX/EAX/R8/R8D | ||
5282 | -c9: BSWAP RCX/ECX/R9/R9D | ||
5283 | -ca: BSWAP RDX/EDX/R10/R10D | ||
5284 | -cb: BSWAP RBX/EBX/R11/R11D | ||
5285 | -cc: BSWAP RSP/ESP/R12/R12D | ||
5286 | -cd: BSWAP RBP/EBP/R13/R13D | ||
5287 | -ce: BSWAP RSI/ESI/R14/R14D | ||
5288 | -cf: BSWAP RDI/EDI/R15/R15D | ||
5289 | -# 0x0f 0xd0-0xdf | ||
5290 | -d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) | ||
5291 | -d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) | ||
5292 | -d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) | ||
5293 | -d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) | ||
5294 | -d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) | ||
5295 | -d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) | ||
5296 | -d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) | ||
5297 | -d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) | ||
5298 | -d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) | ||
5299 | -d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) | ||
5300 | -da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) | ||
5301 | -db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) | ||
5302 | -dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) | ||
5303 | -dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) | ||
5304 | -de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) | ||
5305 | -df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) | ||
5306 | -# 0x0f 0xe0-0xef | ||
5307 | -e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) | ||
5308 | -e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) | ||
5309 | -e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) | ||
5310 | -e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) | ||
5311 | -e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) | ||
5312 | -e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) | ||
5313 | -e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) | ||
5314 | -e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) | ||
5315 | -e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) | ||
5316 | -e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) | ||
5317 | -ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) | ||
5318 | -eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) | ||
5319 | -ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) | ||
5320 | -ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) | ||
5321 | -ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) | ||
5322 | -ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) | ||
5323 | -# 0x0f 0xf0-0xff | ||
5324 | -f0: vlddqu Vx,Mx (F2) | ||
5325 | -f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) | ||
5326 | -f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) | ||
5327 | -f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) | ||
5328 | -f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) | ||
5329 | -f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) | ||
5330 | -f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) | ||
5331 | -f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) | ||
5332 | -f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) | ||
5333 | -f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) | ||
5334 | -fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) | ||
5335 | -fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) | ||
5336 | -fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) | ||
5337 | -fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) | ||
5338 | -fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) | ||
5339 | -ff: | ||
5340 | -EndTable | ||
5341 | - | ||
5342 | -Table: 3-byte opcode 1 (0x0f 0x38) | ||
5343 | -Referrer: 3-byte escape 1 | ||
5344 | -AVXcode: 2 | ||
5345 | -# 0x0f 0x38 0x00-0x0f | ||
5346 | -00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) | ||
5347 | -01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) | ||
5348 | -02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) | ||
5349 | -03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) | ||
5350 | -04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) | ||
5351 | -05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) | ||
5352 | -06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) | ||
5353 | -07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) | ||
5354 | -08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) | ||
5355 | -09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) | ||
5356 | -0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) | ||
5357 | -0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) | ||
5358 | -0c: vpermilps Vx,Hx,Wx (66),(v) | ||
5359 | -0d: vpermilpd Vx,Hx,Wx (66),(v) | ||
5360 | -0e: vtestps Vx,Wx (66),(v) | ||
5361 | -0f: vtestpd Vx,Wx (66),(v) | ||
5362 | -# 0x0f 0x38 0x10-0x1f | ||
5363 | -10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) | ||
5364 | -11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) | ||
5365 | -12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) | ||
5366 | -13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) | ||
5367 | -14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) | ||
5368 | -15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) | ||
5369 | -16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) | ||
5370 | -17: vptest Vx,Wx (66) | ||
5371 | -18: vbroadcastss Vx,Wd (66),(v) | ||
5372 | -19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) | ||
5373 | -1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) | ||
5374 | -1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) | ||
5375 | -1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) | ||
5376 | -1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) | ||
5377 | -1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) | ||
5378 | -1f: vpabsq Vx,Wx (66),(ev) | ||
5379 | -# 0x0f 0x38 0x20-0x2f | ||
5380 | -20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) | ||
5381 | -21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) | ||
5382 | -22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) | ||
5383 | -23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) | ||
5384 | -24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) | ||
5385 | -25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) | ||
5386 | -26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) | ||
5387 | -27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) | ||
5388 | -28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) | ||
5389 | -29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) | ||
5390 | -2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) | ||
5391 | -2b: vpackusdw Vx,Hx,Wx (66),(v1) | ||
5392 | -2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) | ||
5393 | -2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) | ||
5394 | -2e: vmaskmovps Mx,Hx,Vx (66),(v) | ||
5395 | -2f: vmaskmovpd Mx,Hx,Vx (66),(v) | ||
5396 | -# 0x0f 0x38 0x30-0x3f | ||
5397 | -30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) | ||
5398 | -31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) | ||
5399 | -32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) | ||
5400 | -33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) | ||
5401 | -34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) | ||
5402 | -35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) | ||
5403 | -36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) | ||
5404 | -37: vpcmpgtq Vx,Hx,Wx (66),(v1) | ||
5405 | -38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) | ||
5406 | -39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) | ||
5407 | -3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) | ||
5408 | -3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) | ||
5409 | -3c: vpmaxsb Vx,Hx,Wx (66),(v1) | ||
5410 | -3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) | ||
5411 | -3e: vpmaxuw Vx,Hx,Wx (66),(v1) | ||
5412 | -3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) | ||
5413 | -# 0x0f 0x38 0x40-0x8f | ||
5414 | -40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) | ||
5415 | -41: vphminposuw Vdq,Wdq (66),(v1) | ||
5416 | -42: vgetexpps/d Vx,Wx (66),(ev) | ||
5417 | -43: vgetexpss/d Vx,Hx,Wx (66),(ev) | ||
5418 | -44: vplzcntd/q Vx,Wx (66),(ev) | ||
5419 | -45: vpsrlvd/q Vx,Hx,Wx (66),(v) | ||
5420 | -46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) | ||
5421 | -47: vpsllvd/q Vx,Hx,Wx (66),(v) | ||
5422 | -# Skip 0x48-0x4b | ||
5423 | -4c: vrcp14ps/d Vpd,Wpd (66),(ev) | ||
5424 | -4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) | ||
5425 | -4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) | ||
5426 | -4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) | ||
5427 | -# Skip 0x50-0x57 | ||
5428 | -58: vpbroadcastd Vx,Wx (66),(v) | ||
5429 | -59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) | ||
5430 | -5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) | ||
5431 | -5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) | ||
5432 | -# Skip 0x5c-0x63 | ||
5433 | -64: vpblendmd/q Vx,Hx,Wx (66),(ev) | ||
5434 | -65: vblendmps/d Vx,Hx,Wx (66),(ev) | ||
5435 | -66: vpblendmb/w Vx,Hx,Wx (66),(ev) | ||
5436 | -# Skip 0x67-0x74 | ||
5437 | -75: vpermi2b/w Vx,Hx,Wx (66),(ev) | ||
5438 | -76: vpermi2d/q Vx,Hx,Wx (66),(ev) | ||
5439 | -77: vpermi2ps/d Vx,Hx,Wx (66),(ev) | ||
5440 | -78: vpbroadcastb Vx,Wx (66),(v) | ||
5441 | -79: vpbroadcastw Vx,Wx (66),(v) | ||
5442 | -7a: vpbroadcastb Vx,Rv (66),(ev) | ||
5443 | -7b: vpbroadcastw Vx,Rv (66),(ev) | ||
5444 | -7c: vpbroadcastd/q Vx,Rv (66),(ev) | ||
5445 | -7d: vpermt2b/w Vx,Hx,Wx (66),(ev) | ||
5446 | -7e: vpermt2d/q Vx,Hx,Wx (66),(ev) | ||
5447 | -7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) | ||
5448 | -80: INVEPT Gy,Mdq (66) | ||
5449 | -81: INVPID Gy,Mdq (66) | ||
5450 | -82: INVPCID Gy,Mdq (66) | ||
5451 | -83: vpmultishiftqb Vx,Hx,Wx (66),(ev) | ||
5452 | -88: vexpandps/d Vpd,Wpd (66),(ev) | ||
5453 | -89: vpexpandd/q Vx,Wx (66),(ev) | ||
5454 | -8a: vcompressps/d Wx,Vx (66),(ev) | ||
5455 | -8b: vpcompressd/q Wx,Vx (66),(ev) | ||
5456 | -8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) | ||
5457 | -8d: vpermb/w Vx,Hx,Wx (66),(ev) | ||
5458 | -8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) | ||
5459 | -# 0x0f 0x38 0x90-0xbf (FMA) | ||
5460 | -90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) | ||
5461 | -91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) | ||
5462 | -92: vgatherdps/d Vx,Hx,Wx (66),(v) | ||
5463 | -93: vgatherqps/d Vx,Hx,Wx (66),(v) | ||
5464 | -94: | ||
5465 | -95: | ||
5466 | -96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) | ||
5467 | -97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) | ||
5468 | -98: vfmadd132ps/d Vx,Hx,Wx (66),(v) | ||
5469 | -99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5470 | -9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) | ||
5471 | -9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5472 | -9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) | ||
5473 | -9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5474 | -9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) | ||
5475 | -9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5476 | -a0: vpscatterdd/q Wx,Vx (66),(ev) | ||
5477 | -a1: vpscatterqd/q Wx,Vx (66),(ev) | ||
5478 | -a2: vscatterdps/d Wx,Vx (66),(ev) | ||
5479 | -a3: vscatterqps/d Wx,Vx (66),(ev) | ||
5480 | -a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) | ||
5481 | -a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) | ||
5482 | -a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) | ||
5483 | -a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5484 | -aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) | ||
5485 | -ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5486 | -ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) | ||
5487 | -ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5488 | -ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) | ||
5489 | -af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5490 | -b4: vpmadd52luq Vx,Hx,Wx (66),(ev) | ||
5491 | -b5: vpmadd52huq Vx,Hx,Wx (66),(ev) | ||
5492 | -b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) | ||
5493 | -b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) | ||
5494 | -b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) | ||
5495 | -b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5496 | -ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) | ||
5497 | -bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5498 | -bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) | ||
5499 | -bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5500 | -be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) | ||
5501 | -bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) | ||
5502 | -# 0x0f 0x38 0xc0-0xff | ||
5503 | -c4: vpconflictd/q Vx,Wx (66),(ev) | ||
5504 | -c6: Grp18 (1A) | ||
5505 | -c7: Grp19 (1A) | ||
5506 | -c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) | ||
5507 | -c9: sha1msg1 Vdq,Wdq | ||
5508 | -ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) | ||
5509 | -cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) | ||
5510 | -cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) | ||
5511 | -cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) | ||
5512 | -db: VAESIMC Vdq,Wdq (66),(v1) | ||
5513 | -dc: VAESENC Vdq,Hdq,Wdq (66),(v1) | ||
5514 | -dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) | ||
5515 | -de: VAESDEC Vdq,Hdq,Wdq (66),(v1) | ||
5516 | -df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) | ||
5517 | -f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) | ||
5518 | -f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) | ||
5519 | -f2: ANDN Gy,By,Ey (v) | ||
5520 | -f3: Grp17 (1A) | ||
5521 | -f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) | ||
5522 | -f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) | ||
5523 | -f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) | ||
5524 | -EndTable | ||
5525 | - | ||
5526 | -Table: 3-byte opcode 2 (0x0f 0x3a) | ||
5527 | -Referrer: 3-byte escape 2 | ||
5528 | -AVXcode: 3 | ||
5529 | -# 0x0f 0x3a 0x00-0xff | ||
5530 | -00: vpermq Vqq,Wqq,Ib (66),(v) | ||
5531 | -01: vpermpd Vqq,Wqq,Ib (66),(v) | ||
5532 | -02: vpblendd Vx,Hx,Wx,Ib (66),(v) | ||
5533 | -03: valignd/q Vx,Hx,Wx,Ib (66),(ev) | ||
5534 | -04: vpermilps Vx,Wx,Ib (66),(v) | ||
5535 | -05: vpermilpd Vx,Wx,Ib (66),(v) | ||
5536 | -06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) | ||
5537 | -07: | ||
5538 | -08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) | ||
5539 | -09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) | ||
5540 | -0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) | ||
5541 | -0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) | ||
5542 | -0c: vblendps Vx,Hx,Wx,Ib (66) | ||
5543 | -0d: vblendpd Vx,Hx,Wx,Ib (66) | ||
5544 | -0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) | ||
5545 | -0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) | ||
5546 | -14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) | ||
5547 | -15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) | ||
5548 | -16: vpextrd/q Ey,Vdq,Ib (66),(v1) | ||
5549 | -17: vextractps Ed,Vdq,Ib (66),(v1) | ||
5550 | -18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) | ||
5551 | -19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) | ||
5552 | -1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) | ||
5553 | -1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) | ||
5554 | -1d: vcvtps2ph Wx,Vx,Ib (66),(v) | ||
5555 | -1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) | ||
5556 | -1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) | ||
5557 | -20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) | ||
5558 | -21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) | ||
5559 | -22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) | ||
5560 | -23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) | ||
5561 | -25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) | ||
5562 | -26: vgetmantps/d Vx,Wx,Ib (66),(ev) | ||
5563 | -27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) | ||
5564 | -30: kshiftrb/w Vk,Uk,Ib (66),(v) | ||
5565 | -31: kshiftrd/q Vk,Uk,Ib (66),(v) | ||
5566 | -32: kshiftlb/w Vk,Uk,Ib (66),(v) | ||
5567 | -33: kshiftld/q Vk,Uk,Ib (66),(v) | ||
5568 | -38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) | ||
5569 | -39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) | ||
5570 | -3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) | ||
5571 | -3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) | ||
5572 | -3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) | ||
5573 | -3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) | ||
5574 | -40: vdpps Vx,Hx,Wx,Ib (66) | ||
5575 | -41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) | ||
5576 | -42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) | ||
5577 | -43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) | ||
5578 | -44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) | ||
5579 | -46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) | ||
5580 | -4a: vblendvps Vx,Hx,Wx,Lx (66),(v) | ||
5581 | -4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) | ||
5582 | -4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) | ||
5583 | -50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) | ||
5584 | -51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) | ||
5585 | -54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) | ||
5586 | -55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) | ||
5587 | -56: vreduceps/d Vx,Wx,Ib (66),(ev) | ||
5588 | -57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) | ||
5589 | -60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) | ||
5590 | -61: vpcmpestri Vdq,Wdq,Ib (66),(v1) | ||
5591 | -62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) | ||
5592 | -63: vpcmpistri Vdq,Wdq,Ib (66),(v1) | ||
5593 | -66: vfpclassps/d Vk,Wx,Ib (66),(ev) | ||
5594 | -67: vfpclassss/d Vk,Wx,Ib (66),(ev) | ||
5595 | -cc: sha1rnds4 Vdq,Wdq,Ib | ||
5596 | -df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) | ||
5597 | -f0: RORX Gy,Ey,Ib (F2),(v) | ||
5598 | -EndTable | ||
5599 | - | ||
5600 | -GrpTable: Grp1 | ||
5601 | -0: ADD | ||
5602 | -1: OR | ||
5603 | -2: ADC | ||
5604 | -3: SBB | ||
5605 | -4: AND | ||
5606 | -5: SUB | ||
5607 | -6: XOR | ||
5608 | -7: CMP | ||
5609 | -EndTable | ||
5610 | - | ||
5611 | -GrpTable: Grp1A | ||
5612 | -0: POP | ||
5613 | -EndTable | ||
5614 | - | ||
5615 | -GrpTable: Grp2 | ||
5616 | -0: ROL | ||
5617 | -1: ROR | ||
5618 | -2: RCL | ||
5619 | -3: RCR | ||
5620 | -4: SHL/SAL | ||
5621 | -5: SHR | ||
5622 | -6: | ||
5623 | -7: SAR | ||
5624 | -EndTable | ||
5625 | - | ||
5626 | -GrpTable: Grp3_1 | ||
5627 | -0: TEST Eb,Ib | ||
5628 | -1: TEST Eb,Ib | ||
5629 | -2: NOT Eb | ||
5630 | -3: NEG Eb | ||
5631 | -4: MUL AL,Eb | ||
5632 | -5: IMUL AL,Eb | ||
5633 | -6: DIV AL,Eb | ||
5634 | -7: IDIV AL,Eb | ||
5635 | -EndTable | ||
5636 | - | ||
5637 | -GrpTable: Grp3_2 | ||
5638 | -0: TEST Ev,Iz | ||
5639 | -1: | ||
5640 | -2: NOT Ev | ||
5641 | -3: NEG Ev | ||
5642 | -4: MUL rAX,Ev | ||
5643 | -5: IMUL rAX,Ev | ||
5644 | -6: DIV rAX,Ev | ||
5645 | -7: IDIV rAX,Ev | ||
5646 | -EndTable | ||
5647 | - | ||
5648 | -GrpTable: Grp4 | ||
5649 | -0: INC Eb | ||
5650 | -1: DEC Eb | ||
5651 | -EndTable | ||
5652 | - | ||
5653 | -GrpTable: Grp5 | ||
5654 | -0: INC Ev | ||
5655 | -1: DEC Ev | ||
5656 | -# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). | ||
5657 | -2: CALLN Ev (f64) | ||
5658 | -3: CALLF Ep | ||
5659 | -4: JMPN Ev (f64) | ||
5660 | -5: JMPF Mp | ||
5661 | -6: PUSH Ev (d64) | ||
5662 | -7: | ||
5663 | -EndTable | ||
5664 | - | ||
5665 | -GrpTable: Grp6 | ||
5666 | -0: SLDT Rv/Mw | ||
5667 | -1: STR Rv/Mw | ||
5668 | -2: LLDT Ew | ||
5669 | -3: LTR Ew | ||
5670 | -4: VERR Ew | ||
5671 | -5: VERW Ew | ||
5672 | -EndTable | ||
5673 | - | ||
5674 | -GrpTable: Grp7 | ||
5675 | -0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | ||
5676 | -1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) | ||
5677 | -2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) | ||
5678 | -3: LIDT Ms | ||
5679 | -4: SMSW Mw/Rv | ||
5680 | -5: rdpkru (110),(11B) | wrpkru (111),(11B) | ||
5681 | -6: LMSW Ew | ||
5682 | -7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) | ||
5683 | -EndTable | ||
5684 | - | ||
5685 | -GrpTable: Grp8 | ||
5686 | -4: BT | ||
5687 | -5: BTS | ||
5688 | -6: BTR | ||
5689 | -7: BTC | ||
5690 | -EndTable | ||
5691 | - | ||
5692 | -GrpTable: Grp9 | ||
5693 | -1: CMPXCHG8B/16B Mq/Mdq | ||
5694 | -3: xrstors | ||
5695 | -4: xsavec | ||
5696 | -5: xsaves | ||
5697 | -6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) | ||
5698 | -7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) | ||
5699 | -EndTable | ||
5700 | - | ||
5701 | -GrpTable: Grp10 | ||
5702 | -EndTable | ||
5703 | - | ||
5704 | -# Grp11A and Grp11B are expressed as Grp11 in Intel SDM | ||
5705 | -GrpTable: Grp11A | ||
5706 | -0: MOV Eb,Ib | ||
5707 | -7: XABORT Ib (000),(11B) | ||
5708 | -EndTable | ||
5709 | - | ||
5710 | -GrpTable: Grp11B | ||
5711 | -0: MOV Eb,Iz | ||
5712 | -7: XBEGIN Jz (000),(11B) | ||
5713 | -EndTable | ||
5714 | - | ||
5715 | -GrpTable: Grp12 | ||
5716 | -2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) | ||
5717 | -4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) | ||
5718 | -6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) | ||
5719 | -EndTable | ||
5720 | - | ||
5721 | -GrpTable: Grp13 | ||
5722 | -0: vprord/q Hx,Wx,Ib (66),(ev) | ||
5723 | -1: vprold/q Hx,Wx,Ib (66),(ev) | ||
5724 | -2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) | ||
5725 | -4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) | ||
5726 | -6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) | ||
5727 | -EndTable | ||
5728 | - | ||
5729 | -GrpTable: Grp14 | ||
5730 | -2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) | ||
5731 | -3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) | ||
5732 | -6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) | ||
5733 | -7: vpslldq Hx,Ux,Ib (66),(11B),(v1) | ||
5734 | -EndTable | ||
5735 | - | ||
5736 | -GrpTable: Grp15 | ||
5737 | -0: fxsave | RDFSBASE Ry (F3),(11B) | ||
5738 | -1: fxstor | RDGSBASE Ry (F3),(11B) | ||
5739 | -2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) | ||
5740 | -3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) | ||
5741 | -4: XSAVE | ||
5742 | -5: XRSTOR | lfence (11B) | ||
5743 | -6: XSAVEOPT | clwb (66) | mfence (11B) | ||
5744 | -7: clflush | clflushopt (66) | sfence (11B) | ||
5745 | -EndTable | ||
5746 | - | ||
5747 | -GrpTable: Grp16 | ||
5748 | -0: prefetch NTA | ||
5749 | -1: prefetch T0 | ||
5750 | -2: prefetch T1 | ||
5751 | -3: prefetch T2 | ||
5752 | -EndTable | ||
5753 | - | ||
5754 | -GrpTable: Grp17 | ||
5755 | -1: BLSR By,Ey (v) | ||
5756 | -2: BLSMSK By,Ey (v) | ||
5757 | -3: BLSI By,Ey (v) | ||
5758 | -EndTable | ||
5759 | - | ||
5760 | -GrpTable: Grp18 | ||
5761 | -1: vgatherpf0dps/d Wx (66),(ev) | ||
5762 | -2: vgatherpf1dps/d Wx (66),(ev) | ||
5763 | -5: vscatterpf0dps/d Wx (66),(ev) | ||
5764 | -6: vscatterpf1dps/d Wx (66),(ev) | ||
5765 | -EndTable | ||
5766 | - | ||
5767 | -GrpTable: Grp19 | ||
5768 | -1: vgatherpf0qps/d Wx (66),(ev) | ||
5769 | -2: vgatherpf1qps/d Wx (66),(ev) | ||
5770 | -5: vscatterpf0qps/d Wx (66),(ev) | ||
5771 | -6: vscatterpf1qps/d Wx (66),(ev) | ||
5772 | -EndTable | ||
5773 | - | ||
5774 | -# AMD's Prefetch Group | ||
5775 | -GrpTable: GrpP | ||
5776 | -0: PREFETCH | ||
5777 | -1: PREFETCHW | ||
5778 | -EndTable | ||
5779 | - | ||
5780 | -GrpTable: GrpPDLK | ||
5781 | -0: MONTMUL | ||
5782 | -1: XSHA1 | ||
5783 | -2: XSHA2 | ||
5784 | -EndTable | ||
5785 | - | ||
5786 | -GrpTable: GrpRNG | ||
5787 | -0: xstore-rng | ||
5788 | -1: xcrypt-ecb | ||
5789 | -2: xcrypt-cbc | ||
5790 | -4: xcrypt-cfb | ||
5791 | -5: xcrypt-ofb | ||
5792 | -EndTable | ||
5793 | diff --git a/tools/objtool/arch/x86/lib/inat.c b/tools/objtool/arch/x86/lib/inat.c | ||
5794 | new file mode 100644 | ||
5795 | index 000000000000..c1f01a8e9f65 | ||
5796 | --- /dev/null | ||
5797 | +++ b/tools/objtool/arch/x86/lib/inat.c | ||
5798 | @@ -0,0 +1,97 @@ | ||
5799 | +/* | ||
5800 | + * x86 instruction attribute tables | ||
5801 | + * | ||
5802 | + * Written by Masami Hiramatsu <mhiramat@redhat.com> | ||
5803 | + * | ||
5804 | + * This program is free software; you can redistribute it and/or modify | ||
5805 | + * it under the terms of the GNU General Public License as published by | ||
5806 | + * the Free Software Foundation; either version 2 of the License, or | ||
5807 | + * (at your option) any later version. | ||
5808 | + * | ||
5809 | + * This program is distributed in the hope that it will be useful, | ||
5810 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
5811 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
5812 | + * GNU General Public License for more details. | ||
5813 | + * | ||
5814 | + * You should have received a copy of the GNU General Public License | ||
5815 | + * along with this program; if not, write to the Free Software | ||
5816 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
5817 | + * | ||
5818 | + */ | ||
5819 | +#include <asm/insn.h> | ||
5820 | + | ||
5821 | +/* Attribute tables are generated from opcode map */ | ||
5822 | +#include "inat-tables.c" | ||
5823 | + | ||
5824 | +/* Attribute search APIs */ | ||
5825 | +insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) | ||
5826 | +{ | ||
5827 | + return inat_primary_table[opcode]; | ||
5828 | +} | ||
5829 | + | ||
5830 | +int inat_get_last_prefix_id(insn_byte_t last_pfx) | ||
5831 | +{ | ||
5832 | + insn_attr_t lpfx_attr; | ||
5833 | + | ||
5834 | + lpfx_attr = inat_get_opcode_attribute(last_pfx); | ||
5835 | + return inat_last_prefix_id(lpfx_attr); | ||
5836 | +} | ||
5837 | + | ||
5838 | +insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, | ||
5839 | + insn_attr_t esc_attr) | ||
5840 | +{ | ||
5841 | + const insn_attr_t *table; | ||
5842 | + int n; | ||
5843 | + | ||
5844 | + n = inat_escape_id(esc_attr); | ||
5845 | + | ||
5846 | + table = inat_escape_tables[n][0]; | ||
5847 | + if (!table) | ||
5848 | + return 0; | ||
5849 | + if (inat_has_variant(table[opcode]) && lpfx_id) { | ||
5850 | + table = inat_escape_tables[n][lpfx_id]; | ||
5851 | + if (!table) | ||
5852 | + return 0; | ||
5853 | + } | ||
5854 | + return table[opcode]; | ||
5855 | +} | ||
5856 | + | ||
5857 | +insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, | ||
5858 | + insn_attr_t grp_attr) | ||
5859 | +{ | ||
5860 | + const insn_attr_t *table; | ||
5861 | + int n; | ||
5862 | + | ||
5863 | + n = inat_group_id(grp_attr); | ||
5864 | + | ||
5865 | + table = inat_group_tables[n][0]; | ||
5866 | + if (!table) | ||
5867 | + return inat_group_common_attribute(grp_attr); | ||
5868 | + if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { | ||
5869 | + table = inat_group_tables[n][lpfx_id]; | ||
5870 | + if (!table) | ||
5871 | + return inat_group_common_attribute(grp_attr); | ||
5872 | + } | ||
5873 | + return table[X86_MODRM_REG(modrm)] | | ||
5874 | + inat_group_common_attribute(grp_attr); | ||
5875 | +} | ||
5876 | + | ||
5877 | +insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, | ||
5878 | + insn_byte_t vex_p) | ||
5879 | +{ | ||
5880 | + const insn_attr_t *table; | ||
5881 | + if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) | ||
5882 | + return 0; | ||
5883 | + /* At first, this checks the master table */ | ||
5884 | + table = inat_avx_tables[vex_m][0]; | ||
5885 | + if (!table) | ||
5886 | + return 0; | ||
5887 | + if (!inat_is_group(table[opcode]) && vex_p) { | ||
5888 | + /* If this is not a group, get attribute directly */ | ||
5889 | + table = inat_avx_tables[vex_m][vex_p]; | ||
5890 | + if (!table) | ||
5891 | + return 0; | ||
5892 | + } | ||
5893 | + return table[opcode]; | ||
5894 | +} | ||
5895 | + | ||
5896 | diff --git a/tools/objtool/arch/x86/lib/insn.c b/tools/objtool/arch/x86/lib/insn.c | ||
5897 | new file mode 100644 | ||
5898 | index 000000000000..1088eb8f3a5f | ||
5899 | --- /dev/null | ||
5900 | +++ b/tools/objtool/arch/x86/lib/insn.c | ||
5901 | @@ -0,0 +1,606 @@ | ||
5902 | +/* | ||
5903 | + * x86 instruction analysis | ||
5904 | + * | ||
5905 | + * This program is free software; you can redistribute it and/or modify | ||
5906 | + * it under the terms of the GNU General Public License as published by | ||
5907 | + * the Free Software Foundation; either version 2 of the License, or | ||
5908 | + * (at your option) any later version. | ||
5909 | + * | ||
5910 | + * This program is distributed in the hope that it will be useful, | ||
5911 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
5912 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
5913 | + * GNU General Public License for more details. | ||
5914 | + * | ||
5915 | + * You should have received a copy of the GNU General Public License | ||
5916 | + * along with this program; if not, write to the Free Software | ||
5917 | + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
5918 | + * | ||
5919 | + * Copyright (C) IBM Corporation, 2002, 2004, 2009 | ||
5920 | + */ | ||
5921 | + | ||
5922 | +#ifdef __KERNEL__ | ||
5923 | +#include <linux/string.h> | ||
5924 | +#else | ||
5925 | +#include <string.h> | ||
5926 | +#endif | ||
5927 | +#include <asm/inat.h> | ||
5928 | +#include <asm/insn.h> | ||
5929 | + | ||
5930 | +/* Verify next sizeof(t) bytes can be on the same instruction */ | ||
5931 | +#define validate_next(t, insn, n) \ | ||
5932 | + ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) | ||
5933 | + | ||
5934 | +#define __get_next(t, insn) \ | ||
5935 | + ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) | ||
5936 | + | ||
5937 | +#define __peek_nbyte_next(t, insn, n) \ | ||
5938 | + ({ t r = *(t*)((insn)->next_byte + n); r; }) | ||
5939 | + | ||
5940 | +#define get_next(t, insn) \ | ||
5941 | + ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) | ||
5942 | + | ||
5943 | +#define peek_nbyte_next(t, insn, n) \ | ||
5944 | + ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) | ||
5945 | + | ||
5946 | +#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) | ||
5947 | + | ||
5948 | +/** | ||
5949 | + * insn_init() - initialize struct insn | ||
5950 | + * @insn: &struct insn to be initialized | ||
5951 | + * @kaddr: address (in kernel memory) of instruction (or copy thereof) | ||
5952 | + * @x86_64: !0 for 64-bit kernel or 64-bit app | ||
5953 | + */ | ||
5954 | +void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) | ||
5955 | +{ | ||
5956 | + /* | ||
5957 | + * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid | ||
5958 | + * even if the input buffer is long enough to hold them. | ||
5959 | + */ | ||
5960 | + if (buf_len > MAX_INSN_SIZE) | ||
5961 | + buf_len = MAX_INSN_SIZE; | ||
5962 | + | ||
5963 | + memset(insn, 0, sizeof(*insn)); | ||
5964 | + insn->kaddr = kaddr; | ||
5965 | + insn->end_kaddr = kaddr + buf_len; | ||
5966 | + insn->next_byte = kaddr; | ||
5967 | + insn->x86_64 = x86_64 ? 1 : 0; | ||
5968 | + insn->opnd_bytes = 4; | ||
5969 | + if (x86_64) | ||
5970 | + insn->addr_bytes = 8; | ||
5971 | + else | ||
5972 | + insn->addr_bytes = 4; | ||
5973 | +} | ||
5974 | + | ||
5975 | +/** | ||
5976 | + * insn_get_prefixes - scan x86 instruction prefix bytes | ||
5977 | + * @insn: &struct insn containing instruction | ||
5978 | + * | ||
5979 | + * Populates the @insn->prefixes bitmap, and updates @insn->next_byte | ||
5980 | + * to point to the (first) opcode. No effect if @insn->prefixes.got | ||
5981 | + * is already set. | ||
5982 | + */ | ||
5983 | +void insn_get_prefixes(struct insn *insn) | ||
5984 | +{ | ||
5985 | + struct insn_field *prefixes = &insn->prefixes; | ||
5986 | + insn_attr_t attr; | ||
5987 | + insn_byte_t b, lb; | ||
5988 | + int i, nb; | ||
5989 | + | ||
5990 | + if (prefixes->got) | ||
5991 | + return; | ||
5992 | + | ||
5993 | + nb = 0; | ||
5994 | + lb = 0; | ||
5995 | + b = peek_next(insn_byte_t, insn); | ||
5996 | + attr = inat_get_opcode_attribute(b); | ||
5997 | + while (inat_is_legacy_prefix(attr)) { | ||
5998 | + /* Skip if same prefix */ | ||
5999 | + for (i = 0; i < nb; i++) | ||
6000 | + if (prefixes->bytes[i] == b) | ||
6001 | + goto found; | ||
6002 | + if (nb == 4) | ||
6003 | + /* Invalid instruction */ | ||
6004 | + break; | ||
6005 | + prefixes->bytes[nb++] = b; | ||
6006 | + if (inat_is_address_size_prefix(attr)) { | ||
6007 | + /* address size switches 2/4 or 4/8 */ | ||
6008 | + if (insn->x86_64) | ||
6009 | + insn->addr_bytes ^= 12; | ||
6010 | + else | ||
6011 | + insn->addr_bytes ^= 6; | ||
6012 | + } else if (inat_is_operand_size_prefix(attr)) { | ||
6013 | + /* oprand size switches 2/4 */ | ||
6014 | + insn->opnd_bytes ^= 6; | ||
6015 | + } | ||
6016 | +found: | ||
6017 | + prefixes->nbytes++; | ||
6018 | + insn->next_byte++; | ||
6019 | + lb = b; | ||
6020 | + b = peek_next(insn_byte_t, insn); | ||
6021 | + attr = inat_get_opcode_attribute(b); | ||
6022 | + } | ||
6023 | + /* Set the last prefix */ | ||
6024 | + if (lb && lb != insn->prefixes.bytes[3]) { | ||
6025 | + if (unlikely(insn->prefixes.bytes[3])) { | ||
6026 | + /* Swap the last prefix */ | ||
6027 | + b = insn->prefixes.bytes[3]; | ||
6028 | + for (i = 0; i < nb; i++) | ||
6029 | + if (prefixes->bytes[i] == lb) | ||
6030 | + prefixes->bytes[i] = b; | ||
6031 | + } | ||
6032 | + insn->prefixes.bytes[3] = lb; | ||
6033 | + } | ||
6034 | + | ||
6035 | + /* Decode REX prefix */ | ||
6036 | + if (insn->x86_64) { | ||
6037 | + b = peek_next(insn_byte_t, insn); | ||
6038 | + attr = inat_get_opcode_attribute(b); | ||
6039 | + if (inat_is_rex_prefix(attr)) { | ||
6040 | + insn->rex_prefix.value = b; | ||
6041 | + insn->rex_prefix.nbytes = 1; | ||
6042 | + insn->next_byte++; | ||
6043 | + if (X86_REX_W(b)) | ||
6044 | + /* REX.W overrides opnd_size */ | ||
6045 | + insn->opnd_bytes = 8; | ||
6046 | + } | ||
6047 | + } | ||
6048 | + insn->rex_prefix.got = 1; | ||
6049 | + | ||
6050 | + /* Decode VEX prefix */ | ||
6051 | + b = peek_next(insn_byte_t, insn); | ||
6052 | + attr = inat_get_opcode_attribute(b); | ||
6053 | + if (inat_is_vex_prefix(attr)) { | ||
6054 | + insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); | ||
6055 | + if (!insn->x86_64) { | ||
6056 | + /* | ||
6057 | + * In 32-bits mode, if the [7:6] bits (mod bits of | ||
6058 | + * ModRM) on the second byte are not 11b, it is | ||
6059 | + * LDS or LES or BOUND. | ||
6060 | + */ | ||
6061 | + if (X86_MODRM_MOD(b2) != 3) | ||
6062 | + goto vex_end; | ||
6063 | + } | ||
6064 | + insn->vex_prefix.bytes[0] = b; | ||
6065 | + insn->vex_prefix.bytes[1] = b2; | ||
6066 | + if (inat_is_evex_prefix(attr)) { | ||
6067 | + b2 = peek_nbyte_next(insn_byte_t, insn, 2); | ||
6068 | + insn->vex_prefix.bytes[2] = b2; | ||
6069 | + b2 = peek_nbyte_next(insn_byte_t, insn, 3); | ||
6070 | + insn->vex_prefix.bytes[3] = b2; | ||
6071 | + insn->vex_prefix.nbytes = 4; | ||
6072 | + insn->next_byte += 4; | ||
6073 | + if (insn->x86_64 && X86_VEX_W(b2)) | ||
6074 | + /* VEX.W overrides opnd_size */ | ||
6075 | + insn->opnd_bytes = 8; | ||
6076 | + } else if (inat_is_vex3_prefix(attr)) { | ||
6077 | + b2 = peek_nbyte_next(insn_byte_t, insn, 2); | ||
6078 | + insn->vex_prefix.bytes[2] = b2; | ||
6079 | + insn->vex_prefix.nbytes = 3; | ||
6080 | + insn->next_byte += 3; | ||
6081 | + if (insn->x86_64 && X86_VEX_W(b2)) | ||
6082 | + /* VEX.W overrides opnd_size */ | ||
6083 | + insn->opnd_bytes = 8; | ||
6084 | + } else { | ||
6085 | + /* | ||
6086 | + * For VEX2, fake VEX3-like byte#2. | ||
6087 | + * Makes it easier to decode vex.W, vex.vvvv, | ||
6088 | + * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. | ||
6089 | + */ | ||
6090 | + insn->vex_prefix.bytes[2] = b2 & 0x7f; | ||
6091 | + insn->vex_prefix.nbytes = 2; | ||
6092 | + insn->next_byte += 2; | ||
6093 | + } | ||
6094 | + } | ||
6095 | +vex_end: | ||
6096 | + insn->vex_prefix.got = 1; | ||
6097 | + | ||
6098 | + prefixes->got = 1; | ||
6099 | + | ||
6100 | +err_out: | ||
6101 | + return; | ||
6102 | +} | ||
6103 | + | ||
6104 | +/** | ||
6105 | + * insn_get_opcode - collect opcode(s) | ||
6106 | + * @insn: &struct insn containing instruction | ||
6107 | + * | ||
6108 | + * Populates @insn->opcode, updates @insn->next_byte to point past the | ||
6109 | + * opcode byte(s), and set @insn->attr (except for groups). | ||
6110 | + * If necessary, first collects any preceding (prefix) bytes. | ||
6111 | + * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got | ||
6112 | + * is already 1. | ||
6113 | + */ | ||
6114 | +void insn_get_opcode(struct insn *insn) | ||
6115 | +{ | ||
6116 | + struct insn_field *opcode = &insn->opcode; | ||
6117 | + insn_byte_t op; | ||
6118 | + int pfx_id; | ||
6119 | + if (opcode->got) | ||
6120 | + return; | ||
6121 | + if (!insn->prefixes.got) | ||
6122 | + insn_get_prefixes(insn); | ||
6123 | + | ||
6124 | + /* Get first opcode */ | ||
6125 | + op = get_next(insn_byte_t, insn); | ||
6126 | + opcode->bytes[0] = op; | ||
6127 | + opcode->nbytes = 1; | ||
6128 | + | ||
6129 | + /* Check if there is VEX prefix or not */ | ||
6130 | + if (insn_is_avx(insn)) { | ||
6131 | + insn_byte_t m, p; | ||
6132 | + m = insn_vex_m_bits(insn); | ||
6133 | + p = insn_vex_p_bits(insn); | ||
6134 | + insn->attr = inat_get_avx_attribute(op, m, p); | ||
6135 | + if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || | ||
6136 | + (!inat_accept_vex(insn->attr) && | ||
6137 | + !inat_is_group(insn->attr))) | ||
6138 | + insn->attr = 0; /* This instruction is bad */ | ||
6139 | + goto end; /* VEX has only 1 byte for opcode */ | ||
6140 | + } | ||
6141 | + | ||
6142 | + insn->attr = inat_get_opcode_attribute(op); | ||
6143 | + while (inat_is_escape(insn->attr)) { | ||
6144 | + /* Get escaped opcode */ | ||
6145 | + op = get_next(insn_byte_t, insn); | ||
6146 | + opcode->bytes[opcode->nbytes++] = op; | ||
6147 | + pfx_id = insn_last_prefix_id(insn); | ||
6148 | + insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); | ||
6149 | + } | ||
6150 | + if (inat_must_vex(insn->attr)) | ||
6151 | + insn->attr = 0; /* This instruction is bad */ | ||
6152 | +end: | ||
6153 | + opcode->got = 1; | ||
6154 | + | ||
6155 | +err_out: | ||
6156 | + return; | ||
6157 | +} | ||
6158 | + | ||
6159 | +/** | ||
6160 | + * insn_get_modrm - collect ModRM byte, if any | ||
6161 | + * @insn: &struct insn containing instruction | ||
6162 | + * | ||
6163 | + * Populates @insn->modrm and updates @insn->next_byte to point past the | ||
6164 | + * ModRM byte, if any. If necessary, first collects the preceding bytes | ||
6165 | + * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. | ||
6166 | + */ | ||
6167 | +void insn_get_modrm(struct insn *insn) | ||
6168 | +{ | ||
6169 | + struct insn_field *modrm = &insn->modrm; | ||
6170 | + insn_byte_t pfx_id, mod; | ||
6171 | + if (modrm->got) | ||
6172 | + return; | ||
6173 | + if (!insn->opcode.got) | ||
6174 | + insn_get_opcode(insn); | ||
6175 | + | ||
6176 | + if (inat_has_modrm(insn->attr)) { | ||
6177 | + mod = get_next(insn_byte_t, insn); | ||
6178 | + modrm->value = mod; | ||
6179 | + modrm->nbytes = 1; | ||
6180 | + if (inat_is_group(insn->attr)) { | ||
6181 | + pfx_id = insn_last_prefix_id(insn); | ||
6182 | + insn->attr = inat_get_group_attribute(mod, pfx_id, | ||
6183 | + insn->attr); | ||
6184 | + if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) | ||
6185 | + insn->attr = 0; /* This is bad */ | ||
6186 | + } | ||
6187 | + } | ||
6188 | + | ||
6189 | + if (insn->x86_64 && inat_is_force64(insn->attr)) | ||
6190 | + insn->opnd_bytes = 8; | ||
6191 | + modrm->got = 1; | ||
6192 | + | ||
6193 | +err_out: | ||
6194 | + return; | ||
6195 | +} | ||
6196 | + | ||
6197 | + | ||
6198 | +/** | ||
6199 | + * insn_rip_relative() - Does instruction use RIP-relative addressing mode? | ||
6200 | + * @insn: &struct insn containing instruction | ||
6201 | + * | ||
6202 | + * If necessary, first collects the instruction up to and including the | ||
6203 | + * ModRM byte. No effect if @insn->x86_64 is 0. | ||
6204 | + */ | ||
6205 | +int insn_rip_relative(struct insn *insn) | ||
6206 | +{ | ||
6207 | + struct insn_field *modrm = &insn->modrm; | ||
6208 | + | ||
6209 | + if (!insn->x86_64) | ||
6210 | + return 0; | ||
6211 | + if (!modrm->got) | ||
6212 | + insn_get_modrm(insn); | ||
6213 | + /* | ||
6214 | + * For rip-relative instructions, the mod field (top 2 bits) | ||
6215 | + * is zero and the r/m field (bottom 3 bits) is 0x5. | ||
6216 | + */ | ||
6217 | + return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); | ||
6218 | +} | ||
6219 | + | ||
6220 | +/** | ||
6221 | + * insn_get_sib() - Get the SIB byte of instruction | ||
6222 | + * @insn: &struct insn containing instruction | ||
6223 | + * | ||
6224 | + * If necessary, first collects the instruction up to and including the | ||
6225 | + * ModRM byte. | ||
6226 | + */ | ||
6227 | +void insn_get_sib(struct insn *insn) | ||
6228 | +{ | ||
6229 | + insn_byte_t modrm; | ||
6230 | + | ||
6231 | + if (insn->sib.got) | ||
6232 | + return; | ||
6233 | + if (!insn->modrm.got) | ||
6234 | + insn_get_modrm(insn); | ||
6235 | + if (insn->modrm.nbytes) { | ||
6236 | + modrm = (insn_byte_t)insn->modrm.value; | ||
6237 | + if (insn->addr_bytes != 2 && | ||
6238 | + X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { | ||
6239 | + insn->sib.value = get_next(insn_byte_t, insn); | ||
6240 | + insn->sib.nbytes = 1; | ||
6241 | + } | ||
6242 | + } | ||
6243 | + insn->sib.got = 1; | ||
6244 | + | ||
6245 | +err_out: | ||
6246 | + return; | ||
6247 | +} | ||
6248 | + | ||
6249 | + | ||
6250 | +/** | ||
6251 | + * insn_get_displacement() - Get the displacement of instruction | ||
6252 | + * @insn: &struct insn containing instruction | ||
6253 | + * | ||
6254 | + * If necessary, first collects the instruction up to and including the | ||
6255 | + * SIB byte. | ||
6256 | + * Displacement value is sign-expanded. | ||
6257 | + */ | ||
6258 | +void insn_get_displacement(struct insn *insn) | ||
6259 | +{ | ||
6260 | + insn_byte_t mod, rm, base; | ||
6261 | + | ||
6262 | + if (insn->displacement.got) | ||
6263 | + return; | ||
6264 | + if (!insn->sib.got) | ||
6265 | + insn_get_sib(insn); | ||
6266 | + if (insn->modrm.nbytes) { | ||
6267 | + /* | ||
6268 | + * Interpreting the modrm byte: | ||
6269 | + * mod = 00 - no displacement fields (exceptions below) | ||
6270 | + * mod = 01 - 1-byte displacement field | ||
6271 | + * mod = 10 - displacement field is 4 bytes, or 2 bytes if | ||
6272 | + * address size = 2 (0x67 prefix in 32-bit mode) | ||
6273 | + * mod = 11 - no memory operand | ||
6274 | + * | ||
6275 | + * If address size = 2... | ||
6276 | + * mod = 00, r/m = 110 - displacement field is 2 bytes | ||
6277 | + * | ||
6278 | + * If address size != 2... | ||
6279 | + * mod != 11, r/m = 100 - SIB byte exists | ||
6280 | + * mod = 00, SIB base = 101 - displacement field is 4 bytes | ||
6281 | + * mod = 00, r/m = 101 - rip-relative addressing, displacement | ||
6282 | + * field is 4 bytes | ||
6283 | + */ | ||
6284 | + mod = X86_MODRM_MOD(insn->modrm.value); | ||
6285 | + rm = X86_MODRM_RM(insn->modrm.value); | ||
6286 | + base = X86_SIB_BASE(insn->sib.value); | ||
6287 | + if (mod == 3) | ||
6288 | + goto out; | ||
6289 | + if (mod == 1) { | ||
6290 | + insn->displacement.value = get_next(signed char, insn); | ||
6291 | + insn->displacement.nbytes = 1; | ||
6292 | + } else if (insn->addr_bytes == 2) { | ||
6293 | + if ((mod == 0 && rm == 6) || mod == 2) { | ||
6294 | + insn->displacement.value = | ||
6295 | + get_next(short, insn); | ||
6296 | + insn->displacement.nbytes = 2; | ||
6297 | + } | ||
6298 | + } else { | ||
6299 | + if ((mod == 0 && rm == 5) || mod == 2 || | ||
6300 | + (mod == 0 && base == 5)) { | ||
6301 | + insn->displacement.value = get_next(int, insn); | ||
6302 | + insn->displacement.nbytes = 4; | ||
6303 | + } | ||
6304 | + } | ||
6305 | + } | ||
6306 | +out: | ||
6307 | + insn->displacement.got = 1; | ||
6308 | + | ||
6309 | +err_out: | ||
6310 | + return; | ||
6311 | +} | ||
6312 | + | ||
6313 | +/* Decode moffset16/32/64. Return 0 if failed */ | ||
6314 | +static int __get_moffset(struct insn *insn) | ||
6315 | +{ | ||
6316 | + switch (insn->addr_bytes) { | ||
6317 | + case 2: | ||
6318 | + insn->moffset1.value = get_next(short, insn); | ||
6319 | + insn->moffset1.nbytes = 2; | ||
6320 | + break; | ||
6321 | + case 4: | ||
6322 | + insn->moffset1.value = get_next(int, insn); | ||
6323 | + insn->moffset1.nbytes = 4; | ||
6324 | + break; | ||
6325 | + case 8: | ||
6326 | + insn->moffset1.value = get_next(int, insn); | ||
6327 | + insn->moffset1.nbytes = 4; | ||
6328 | + insn->moffset2.value = get_next(int, insn); | ||
6329 | + insn->moffset2.nbytes = 4; | ||
6330 | + break; | ||
6331 | + default: /* opnd_bytes must be modified manually */ | ||
6332 | + goto err_out; | ||
6333 | + } | ||
6334 | + insn->moffset1.got = insn->moffset2.got = 1; | ||
6335 | + | ||
6336 | + return 1; | ||
6337 | + | ||
6338 | +err_out: | ||
6339 | + return 0; | ||
6340 | +} | ||
6341 | + | ||
6342 | +/* Decode imm v32(Iz). Return 0 if failed */ | ||
6343 | +static int __get_immv32(struct insn *insn) | ||
6344 | +{ | ||
6345 | + switch (insn->opnd_bytes) { | ||
6346 | + case 2: | ||
6347 | + insn->immediate.value = get_next(short, insn); | ||
6348 | + insn->immediate.nbytes = 2; | ||
6349 | + break; | ||
6350 | + case 4: | ||
6351 | + case 8: | ||
6352 | + insn->immediate.value = get_next(int, insn); | ||
6353 | + insn->immediate.nbytes = 4; | ||
6354 | + break; | ||
6355 | + default: /* opnd_bytes must be modified manually */ | ||
6356 | + goto err_out; | ||
6357 | + } | ||
6358 | + | ||
6359 | + return 1; | ||
6360 | + | ||
6361 | +err_out: | ||
6362 | + return 0; | ||
6363 | +} | ||
6364 | + | ||
6365 | +/* Decode imm v64(Iv/Ov), Return 0 if failed */ | ||
6366 | +static int __get_immv(struct insn *insn) | ||
6367 | +{ | ||
6368 | + switch (insn->opnd_bytes) { | ||
6369 | + case 2: | ||
6370 | + insn->immediate1.value = get_next(short, insn); | ||
6371 | + insn->immediate1.nbytes = 2; | ||
6372 | + break; | ||
6373 | + case 4: | ||
6374 | + insn->immediate1.value = get_next(int, insn); | ||
6375 | + insn->immediate1.nbytes = 4; | ||
6376 | + break; | ||
6377 | + case 8: | ||
6378 | + insn->immediate1.value = get_next(int, insn); | ||
6379 | + insn->immediate1.nbytes = 4; | ||
6380 | + insn->immediate2.value = get_next(int, insn); | ||
6381 | + insn->immediate2.nbytes = 4; | ||
6382 | + break; | ||
6383 | + default: /* opnd_bytes must be modified manually */ | ||
6384 | + goto err_out; | ||
6385 | + } | ||
6386 | + insn->immediate1.got = insn->immediate2.got = 1; | ||
6387 | + | ||
6388 | + return 1; | ||
6389 | +err_out: | ||
6390 | + return 0; | ||
6391 | +} | ||
6392 | + | ||
6393 | +/* Decode ptr16:16/32(Ap) */ | ||
6394 | +static int __get_immptr(struct insn *insn) | ||
6395 | +{ | ||
6396 | + switch (insn->opnd_bytes) { | ||
6397 | + case 2: | ||
6398 | + insn->immediate1.value = get_next(short, insn); | ||
6399 | + insn->immediate1.nbytes = 2; | ||
6400 | + break; | ||
6401 | + case 4: | ||
6402 | + insn->immediate1.value = get_next(int, insn); | ||
6403 | + insn->immediate1.nbytes = 4; | ||
6404 | + break; | ||
6405 | + case 8: | ||
6406 | + /* ptr16:64 is not exist (no segment) */ | ||
6407 | + return 0; | ||
6408 | + default: /* opnd_bytes must be modified manually */ | ||
6409 | + goto err_out; | ||
6410 | + } | ||
6411 | + insn->immediate2.value = get_next(unsigned short, insn); | ||
6412 | + insn->immediate2.nbytes = 2; | ||
6413 | + insn->immediate1.got = insn->immediate2.got = 1; | ||
6414 | + | ||
6415 | + return 1; | ||
6416 | +err_out: | ||
6417 | + return 0; | ||
6418 | +} | ||
6419 | + | ||
6420 | +/** | ||
6421 | + * insn_get_immediate() - Get the immediates of instruction | ||
6422 | + * @insn: &struct insn containing instruction | ||
6423 | + * | ||
6424 | + * If necessary, first collects the instruction up to and including the | ||
6425 | + * displacement bytes. | ||
6426 | + * Basically, most of immediates are sign-expanded. Unsigned-value can be | ||
6427 | + * get by bit masking with ((1 << (nbytes * 8)) - 1) | ||
6428 | + */ | ||
6429 | +void insn_get_immediate(struct insn *insn) | ||
6430 | +{ | ||
6431 | + if (insn->immediate.got) | ||
6432 | + return; | ||
6433 | + if (!insn->displacement.got) | ||
6434 | + insn_get_displacement(insn); | ||
6435 | + | ||
6436 | + if (inat_has_moffset(insn->attr)) { | ||
6437 | + if (!__get_moffset(insn)) | ||
6438 | + goto err_out; | ||
6439 | + goto done; | ||
6440 | + } | ||
6441 | + | ||
6442 | + if (!inat_has_immediate(insn->attr)) | ||
6443 | + /* no immediates */ | ||
6444 | + goto done; | ||
6445 | + | ||
6446 | + switch (inat_immediate_size(insn->attr)) { | ||
6447 | + case INAT_IMM_BYTE: | ||
6448 | + insn->immediate.value = get_next(signed char, insn); | ||
6449 | + insn->immediate.nbytes = 1; | ||
6450 | + break; | ||
6451 | + case INAT_IMM_WORD: | ||
6452 | + insn->immediate.value = get_next(short, insn); | ||
6453 | + insn->immediate.nbytes = 2; | ||
6454 | + break; | ||
6455 | + case INAT_IMM_DWORD: | ||
6456 | + insn->immediate.value = get_next(int, insn); | ||
6457 | + insn->immediate.nbytes = 4; | ||
6458 | + break; | ||
6459 | + case INAT_IMM_QWORD: | ||
6460 | + insn->immediate1.value = get_next(int, insn); | ||
6461 | + insn->immediate1.nbytes = 4; | ||
6462 | + insn->immediate2.value = get_next(int, insn); | ||
6463 | + insn->immediate2.nbytes = 4; | ||
6464 | + break; | ||
6465 | + case INAT_IMM_PTR: | ||
6466 | + if (!__get_immptr(insn)) | ||
6467 | + goto err_out; | ||
6468 | + break; | ||
6469 | + case INAT_IMM_VWORD32: | ||
6470 | + if (!__get_immv32(insn)) | ||
6471 | + goto err_out; | ||
6472 | + break; | ||
6473 | + case INAT_IMM_VWORD: | ||
6474 | + if (!__get_immv(insn)) | ||
6475 | + goto err_out; | ||
6476 | + break; | ||
6477 | + default: | ||
6478 | + /* Here, insn must have an immediate, but failed */ | ||
6479 | + goto err_out; | ||
6480 | + } | ||
6481 | + if (inat_has_second_immediate(insn->attr)) { | ||
6482 | + insn->immediate2.value = get_next(signed char, insn); | ||
6483 | + insn->immediate2.nbytes = 1; | ||
6484 | + } | ||
6485 | +done: | ||
6486 | + insn->immediate.got = 1; | ||
6487 | + | ||
6488 | +err_out: | ||
6489 | + return; | ||
6490 | +} | ||
6491 | + | ||
6492 | +/** | ||
6493 | + * insn_get_length() - Get the length of instruction | ||
6494 | + * @insn: &struct insn containing instruction | ||
6495 | + * | ||
6496 | + * If necessary, first collects the instruction up to and including the | ||
6497 | + * immediates bytes. | ||
6498 | + */ | ||
6499 | +void insn_get_length(struct insn *insn) | ||
6500 | +{ | ||
6501 | + if (insn->length) | ||
6502 | + return; | ||
6503 | + if (!insn->immediate.got) | ||
6504 | + insn_get_immediate(insn); | ||
6505 | + insn->length = (unsigned char)((unsigned long)insn->next_byte | ||
6506 | + - (unsigned long)insn->kaddr); | ||
6507 | +} | ||
6508 | diff --git a/tools/objtool/arch/x86/lib/x86-opcode-map.txt b/tools/objtool/arch/x86/lib/x86-opcode-map.txt | ||
6509 | new file mode 100644 | ||
6510 | index 000000000000..1754e094bc28 | ||
6511 | --- /dev/null | ||
6512 | +++ b/tools/objtool/arch/x86/lib/x86-opcode-map.txt | ||
6513 | @@ -0,0 +1,1063 @@ | ||
6514 | +# x86 Opcode Maps | ||
6515 | +# | ||
6516 | +# This is (mostly) based on following documentations. | ||
6517 | +# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C | ||
6518 | +# (#326018-047US, June 2013) | ||
6519 | +# | ||
6520 | +#<Opcode maps> | ||
6521 | +# Table: table-name | ||
6522 | +# Referrer: escaped-name | ||
6523 | +# AVXcode: avx-code | ||
6524 | +# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] | ||
6525 | +# (or) | ||
6526 | +# opcode: escape # escaped-name | ||
6527 | +# EndTable | ||
6528 | +# | ||
6529 | +# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix | ||
6530 | +# mnemonics that begin with lowercase 'k' accept a VEX prefix | ||
6531 | +# | ||
6532 | +#<group maps> | ||
6533 | +# GrpTable: GrpXXX | ||
6534 | +# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] | ||
6535 | +# EndTable | ||
6536 | +# | ||
6537 | +# AVX Superscripts | ||
6538 | +# (ev): this opcode requires EVEX prefix. | ||
6539 | +# (evo): this opcode is changed by EVEX prefix (EVEX opcode) | ||
6540 | +# (v): this opcode requires VEX prefix. | ||
6541 | +# (v1): this opcode only supports 128bit VEX. | ||
6542 | +# | ||
6543 | +# Last Prefix Superscripts | ||
6544 | +# - (66): the last prefix is 0x66 | ||
6545 | +# - (F3): the last prefix is 0xF3 | ||
6546 | +# - (F2): the last prefix is 0xF2 | ||
6547 | +# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) | ||
6548 | +# - (66&F2): Both 0x66 and 0xF2 prefixes are specified. | ||
6549 | + | ||
6550 | +Table: one byte opcode | ||
6551 | +Referrer: | ||
6552 | +AVXcode: | ||
6553 | +# 0x00 - 0x0f | ||
6554 | +00: ADD Eb,Gb | ||
6555 | +01: ADD Ev,Gv | ||
6556 | +02: ADD Gb,Eb | ||
6557 | +03: ADD Gv,Ev | ||
6558 | +04: ADD AL,Ib | ||
6559 | +05: ADD rAX,Iz | ||
6560 | +06: PUSH ES (i64) | ||
6561 | +07: POP ES (i64) | ||
6562 | +08: OR Eb,Gb | ||
6563 | +09: OR Ev,Gv | ||
6564 | +0a: OR Gb,Eb | ||
6565 | +0b: OR Gv,Ev | ||
6566 | +0c: OR AL,Ib | ||
6567 | +0d: OR rAX,Iz | ||
6568 | +0e: PUSH CS (i64) | ||
6569 | +0f: escape # 2-byte escape | ||
6570 | +# 0x10 - 0x1f | ||
6571 | +10: ADC Eb,Gb | ||
6572 | +11: ADC Ev,Gv | ||
6573 | +12: ADC Gb,Eb | ||
6574 | +13: ADC Gv,Ev | ||
6575 | +14: ADC AL,Ib | ||
6576 | +15: ADC rAX,Iz | ||
6577 | +16: PUSH SS (i64) | ||
6578 | +17: POP SS (i64) | ||
6579 | +18: SBB Eb,Gb | ||
6580 | +19: SBB Ev,Gv | ||
6581 | +1a: SBB Gb,Eb | ||
6582 | +1b: SBB Gv,Ev | ||
6583 | +1c: SBB AL,Ib | ||
6584 | +1d: SBB rAX,Iz | ||
6585 | +1e: PUSH DS (i64) | ||
6586 | +1f: POP DS (i64) | ||
6587 | +# 0x20 - 0x2f | ||
6588 | +20: AND Eb,Gb | ||
6589 | +21: AND Ev,Gv | ||
6590 | +22: AND Gb,Eb | ||
6591 | +23: AND Gv,Ev | ||
6592 | +24: AND AL,Ib | ||
6593 | +25: AND rAx,Iz | ||
6594 | +26: SEG=ES (Prefix) | ||
6595 | +27: DAA (i64) | ||
6596 | +28: SUB Eb,Gb | ||
6597 | +29: SUB Ev,Gv | ||
6598 | +2a: SUB Gb,Eb | ||
6599 | +2b: SUB Gv,Ev | ||
6600 | +2c: SUB AL,Ib | ||
6601 | +2d: SUB rAX,Iz | ||
6602 | +2e: SEG=CS (Prefix) | ||
6603 | +2f: DAS (i64) | ||
6604 | +# 0x30 - 0x3f | ||
6605 | +30: XOR Eb,Gb | ||
6606 | +31: XOR Ev,Gv | ||
6607 | +32: XOR Gb,Eb | ||
6608 | +33: XOR Gv,Ev | ||
6609 | +34: XOR AL,Ib | ||
6610 | +35: XOR rAX,Iz | ||
6611 | +36: SEG=SS (Prefix) | ||
6612 | +37: AAA (i64) | ||
6613 | +38: CMP Eb,Gb | ||
6614 | +39: CMP Ev,Gv | ||
6615 | +3a: CMP Gb,Eb | ||
6616 | +3b: CMP Gv,Ev | ||
6617 | +3c: CMP AL,Ib | ||
6618 | +3d: CMP rAX,Iz | ||
6619 | +3e: SEG=DS (Prefix) | ||
6620 | +3f: AAS (i64) | ||
6621 | +# 0x40 - 0x4f | ||
6622 | +40: INC eAX (i64) | REX (o64) | ||
6623 | +41: INC eCX (i64) | REX.B (o64) | ||
6624 | +42: INC eDX (i64) | REX.X (o64) | ||
6625 | +43: INC eBX (i64) | REX.XB (o64) | ||
6626 | +44: INC eSP (i64) | REX.R (o64) | ||
6627 | +45: INC eBP (i64) | REX.RB (o64) | ||
6628 | +46: INC eSI (i64) | REX.RX (o64) | ||
6629 | +47: INC eDI (i64) | REX.RXB (o64) | ||
6630 | +48: DEC eAX (i64) | REX.W (o64) | ||
6631 | +49: DEC eCX (i64) | REX.WB (o64) | ||
6632 | +4a: DEC eDX (i64) | REX.WX (o64) | ||
6633 | +4b: DEC eBX (i64) | REX.WXB (o64) | ||
6634 | +4c: DEC eSP (i64) | REX.WR (o64) | ||
6635 | +4d: DEC eBP (i64) | REX.WRB (o64) | ||
6636 | +4e: DEC eSI (i64) | REX.WRX (o64) | ||
6637 | +4f: DEC eDI (i64) | REX.WRXB (o64) | ||
6638 | +# 0x50 - 0x5f | ||
6639 | +50: PUSH rAX/r8 (d64) | ||
6640 | +51: PUSH rCX/r9 (d64) | ||
6641 | +52: PUSH rDX/r10 (d64) | ||
6642 | +53: PUSH rBX/r11 (d64) | ||
6643 | +54: PUSH rSP/r12 (d64) | ||
6644 | +55: PUSH rBP/r13 (d64) | ||
6645 | +56: PUSH rSI/r14 (d64) | ||
6646 | +57: PUSH rDI/r15 (d64) | ||
6647 | +58: POP rAX/r8 (d64) | ||
6648 | +59: POP rCX/r9 (d64) | ||
6649 | +5a: POP rDX/r10 (d64) | ||
6650 | +5b: POP rBX/r11 (d64) | ||
6651 | +5c: POP rSP/r12 (d64) | ||
6652 | +5d: POP rBP/r13 (d64) | ||
6653 | +5e: POP rSI/r14 (d64) | ||
6654 | +5f: POP rDI/r15 (d64) | ||
6655 | +# 0x60 - 0x6f | ||
6656 | +60: PUSHA/PUSHAD (i64) | ||
6657 | +61: POPA/POPAD (i64) | ||
6658 | +62: BOUND Gv,Ma (i64) | EVEX (Prefix) | ||
6659 | +63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) | ||
6660 | +64: SEG=FS (Prefix) | ||
6661 | +65: SEG=GS (Prefix) | ||
6662 | +66: Operand-Size (Prefix) | ||
6663 | +67: Address-Size (Prefix) | ||
6664 | +68: PUSH Iz (d64) | ||
6665 | +69: IMUL Gv,Ev,Iz | ||
6666 | +6a: PUSH Ib (d64) | ||
6667 | +6b: IMUL Gv,Ev,Ib | ||
6668 | +6c: INS/INSB Yb,DX | ||
6669 | +6d: INS/INSW/INSD Yz,DX | ||
6670 | +6e: OUTS/OUTSB DX,Xb | ||
6671 | +6f: OUTS/OUTSW/OUTSD DX,Xz | ||
6672 | +# 0x70 - 0x7f | ||
6673 | +70: JO Jb | ||
6674 | +71: JNO Jb | ||
6675 | +72: JB/JNAE/JC Jb | ||
6676 | +73: JNB/JAE/JNC Jb | ||
6677 | +74: JZ/JE Jb | ||
6678 | +75: JNZ/JNE Jb | ||
6679 | +76: JBE/JNA Jb | ||
6680 | +77: JNBE/JA Jb | ||
6681 | +78: JS Jb | ||
6682 | +79: JNS Jb | ||
6683 | +7a: JP/JPE Jb | ||
6684 | +7b: JNP/JPO Jb | ||
6685 | +7c: JL/JNGE Jb | ||
6686 | +7d: JNL/JGE Jb | ||
6687 | +7e: JLE/JNG Jb | ||
6688 | +7f: JNLE/JG Jb | ||
6689 | +# 0x80 - 0x8f | ||
6690 | +80: Grp1 Eb,Ib (1A) | ||
6691 | +81: Grp1 Ev,Iz (1A) | ||
6692 | +82: Grp1 Eb,Ib (1A),(i64) | ||
6693 | +83: Grp1 Ev,Ib (1A) | ||
6694 | +84: TEST Eb,Gb | ||
6695 | +85: TEST Ev,Gv | ||
6696 | +86: XCHG Eb,Gb | ||
6697 | +87: XCHG Ev,Gv | ||
6698 | +88: MOV Eb,Gb | ||
6699 | +89: MOV Ev,Gv | ||
6700 | +8a: MOV Gb,Eb | ||
6701 | +8b: MOV Gv,Ev | ||
6702 | +8c: MOV Ev,Sw | ||
6703 | +8d: LEA Gv,M | ||
6704 | +8e: MOV Sw,Ew | ||
6705 | +8f: Grp1A (1A) | POP Ev (d64) | ||
6706 | +# 0x90 - 0x9f | ||
6707 | +90: NOP | PAUSE (F3) | XCHG r8,rAX | ||
6708 | +91: XCHG rCX/r9,rAX | ||
6709 | +92: XCHG rDX/r10,rAX | ||
6710 | +93: XCHG rBX/r11,rAX | ||
6711 | +94: XCHG rSP/r12,rAX | ||
6712 | +95: XCHG rBP/r13,rAX | ||
6713 | +96: XCHG rSI/r14,rAX | ||
6714 | +97: XCHG rDI/r15,rAX | ||
6715 | +98: CBW/CWDE/CDQE | ||
6716 | +99: CWD/CDQ/CQO | ||
6717 | +9a: CALLF Ap (i64) | ||
6718 | +9b: FWAIT/WAIT | ||
6719 | +9c: PUSHF/D/Q Fv (d64) | ||
6720 | +9d: POPF/D/Q Fv (d64) | ||
6721 | +9e: SAHF | ||
6722 | +9f: LAHF | ||
6723 | +# 0xa0 - 0xaf | ||
6724 | +a0: MOV AL,Ob | ||
6725 | +a1: MOV rAX,Ov | ||
6726 | +a2: MOV Ob,AL | ||
6727 | +a3: MOV Ov,rAX | ||
6728 | +a4: MOVS/B Yb,Xb | ||
6729 | +a5: MOVS/W/D/Q Yv,Xv | ||
6730 | +a6: CMPS/B Xb,Yb | ||
6731 | +a7: CMPS/W/D Xv,Yv | ||
6732 | +a8: TEST AL,Ib | ||
6733 | +a9: TEST rAX,Iz | ||
6734 | +aa: STOS/B Yb,AL | ||
6735 | +ab: STOS/W/D/Q Yv,rAX | ||
6736 | +ac: LODS/B AL,Xb | ||
6737 | +ad: LODS/W/D/Q rAX,Xv | ||
6738 | +ae: SCAS/B AL,Yb | ||
6739 | +# Note: The May 2011 Intel manual shows Xv for the second parameter of the | ||
6740 | +# next instruction but Yv is correct | ||
6741 | +af: SCAS/W/D/Q rAX,Yv | ||
6742 | +# 0xb0 - 0xbf | ||
6743 | +b0: MOV AL/R8L,Ib | ||
6744 | +b1: MOV CL/R9L,Ib | ||
6745 | +b2: MOV DL/R10L,Ib | ||
6746 | +b3: MOV BL/R11L,Ib | ||
6747 | +b4: MOV AH/R12L,Ib | ||
6748 | +b5: MOV CH/R13L,Ib | ||
6749 | +b6: MOV DH/R14L,Ib | ||
6750 | +b7: MOV BH/R15L,Ib | ||
6751 | +b8: MOV rAX/r8,Iv | ||
6752 | +b9: MOV rCX/r9,Iv | ||
6753 | +ba: MOV rDX/r10,Iv | ||
6754 | +bb: MOV rBX/r11,Iv | ||
6755 | +bc: MOV rSP/r12,Iv | ||
6756 | +bd: MOV rBP/r13,Iv | ||
6757 | +be: MOV rSI/r14,Iv | ||
6758 | +bf: MOV rDI/r15,Iv | ||
6759 | +# 0xc0 - 0xcf | ||
6760 | +c0: Grp2 Eb,Ib (1A) | ||
6761 | +c1: Grp2 Ev,Ib (1A) | ||
6762 | +c2: RETN Iw (f64) | ||
6763 | +c3: RETN | ||
6764 | +c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) | ||
6765 | +c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) | ||
6766 | +c6: Grp11A Eb,Ib (1A) | ||
6767 | +c7: Grp11B Ev,Iz (1A) | ||
6768 | +c8: ENTER Iw,Ib | ||
6769 | +c9: LEAVE (d64) | ||
6770 | +ca: RETF Iw | ||
6771 | +cb: RETF | ||
6772 | +cc: INT3 | ||
6773 | +cd: INT Ib | ||
6774 | +ce: INTO (i64) | ||
6775 | +cf: IRET/D/Q | ||
6776 | +# 0xd0 - 0xdf | ||
6777 | +d0: Grp2 Eb,1 (1A) | ||
6778 | +d1: Grp2 Ev,1 (1A) | ||
6779 | +d2: Grp2 Eb,CL (1A) | ||
6780 | +d3: Grp2 Ev,CL (1A) | ||
6781 | +d4: AAM Ib (i64) | ||
6782 | +d5: AAD Ib (i64) | ||
6783 | +d6: | ||
6784 | +d7: XLAT/XLATB | ||
6785 | +d8: ESC | ||
6786 | +d9: ESC | ||
6787 | +da: ESC | ||
6788 | +db: ESC | ||
6789 | +dc: ESC | ||
6790 | +dd: ESC | ||
6791 | +de: ESC | ||
6792 | +df: ESC | ||
6793 | +# 0xe0 - 0xef | ||
6794 | +# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix | ||
6795 | +# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation | ||
6796 | +# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD. | ||
6797 | +e0: LOOPNE/LOOPNZ Jb (f64) | ||
6798 | +e1: LOOPE/LOOPZ Jb (f64) | ||
6799 | +e2: LOOP Jb (f64) | ||
6800 | +e3: JrCXZ Jb (f64) | ||
6801 | +e4: IN AL,Ib | ||
6802 | +e5: IN eAX,Ib | ||
6803 | +e6: OUT Ib,AL | ||
6804 | +e7: OUT Ib,eAX | ||
6805 | +# With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset | ||
6806 | +# in "near" jumps and calls is 16-bit. For CALL, | ||
6807 | +# push of return address is 16-bit wide, RSP is decremented by 2 | ||
6808 | +# but is not truncated to 16 bits, unlike RIP. | ||
6809 | +e8: CALL Jz (f64) | ||
6810 | +e9: JMP-near Jz (f64) | ||
6811 | +ea: JMP-far Ap (i64) | ||
6812 | +eb: JMP-short Jb (f64) | ||
6813 | +ec: IN AL,DX | ||
6814 | +ed: IN eAX,DX | ||
6815 | +ee: OUT DX,AL | ||
6816 | +ef: OUT DX,eAX | ||
6817 | +# 0xf0 - 0xff | ||
6818 | +f0: LOCK (Prefix) | ||
6819 | +f1: | ||
6820 | +f2: REPNE (Prefix) | XACQUIRE (Prefix) | ||
6821 | +f3: REP/REPE (Prefix) | XRELEASE (Prefix) | ||
6822 | +f4: HLT | ||
6823 | +f5: CMC | ||
6824 | +f6: Grp3_1 Eb (1A) | ||
6825 | +f7: Grp3_2 Ev (1A) | ||
6826 | +f8: CLC | ||
6827 | +f9: STC | ||
6828 | +fa: CLI | ||
6829 | +fb: STI | ||
6830 | +fc: CLD | ||
6831 | +fd: STD | ||
6832 | +fe: Grp4 (1A) | ||
6833 | +ff: Grp5 (1A) | ||
6834 | +EndTable | ||
6835 | + | ||
6836 | +Table: 2-byte opcode (0x0f) | ||
6837 | +Referrer: 2-byte escape | ||
6838 | +AVXcode: 1 | ||
6839 | +# 0x0f 0x00-0x0f | ||
6840 | +00: Grp6 (1A) | ||
6841 | +01: Grp7 (1A) | ||
6842 | +02: LAR Gv,Ew | ||
6843 | +03: LSL Gv,Ew | ||
6844 | +04: | ||
6845 | +05: SYSCALL (o64) | ||
6846 | +06: CLTS | ||
6847 | +07: SYSRET (o64) | ||
6848 | +08: INVD | ||
6849 | +09: WBINVD | ||
6850 | +0a: | ||
6851 | +0b: UD2 (1B) | ||
6852 | +0c: | ||
6853 | +# AMD's prefetch group. Intel supports prefetchw(/1) only. | ||
6854 | +0d: GrpP | ||
6855 | +0e: FEMMS | ||
6856 | +# 3DNow! uses the last imm byte as opcode extension. | ||
6857 | +0f: 3DNow! Pq,Qq,Ib | ||
6858 | +# 0x0f 0x10-0x1f | ||
6859 | +# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands | ||
6860 | +# but it actually has operands. And also, vmovss and vmovsd only accept 128bit. | ||
6861 | +# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. | ||
6862 | +# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming | ||
6863 | +# Reference A.1 | ||
6864 | +10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) | ||
6865 | +11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) | ||
6866 | +12: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2) | ||
6867 | +13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) | ||
6868 | +14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) | ||
6869 | +15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) | ||
6870 | +16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) | ||
6871 | +17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) | ||
6872 | +18: Grp16 (1A) | ||
6873 | +19: | ||
6874 | +# Intel SDM opcode map does not list MPX instructions. For now using Gv for | ||
6875 | +# bnd registers and Ev for everything else is OK because the instruction | ||
6876 | +# decoder does not use the information except as an indication that there is | ||
6877 | +# a ModR/M byte. | ||
6878 | +1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev | ||
6879 | +1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv | ||
6880 | +1c: | ||
6881 | +1d: | ||
6882 | +1e: | ||
6883 | +1f: NOP Ev | ||
6884 | +# 0x0f 0x20-0x2f | ||
6885 | +20: MOV Rd,Cd | ||
6886 | +21: MOV Rd,Dd | ||
6887 | +22: MOV Cd,Rd | ||
6888 | +23: MOV Dd,Rd | ||
6889 | +24: | ||
6890 | +25: | ||
6891 | +26: | ||
6892 | +27: | ||
6893 | +28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) | ||
6894 | +29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) | ||
6895 | +2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) | ||
6896 | +2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) | ||
6897 | +2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) | ||
6898 | +2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) | ||
6899 | +2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) | ||
6900 | +2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) | ||
6901 | +# 0x0f 0x30-0x3f | ||
6902 | +30: WRMSR | ||
6903 | +31: RDTSC | ||
6904 | +32: RDMSR | ||
6905 | +33: RDPMC | ||
6906 | +34: SYSENTER | ||
6907 | +35: SYSEXIT | ||
6908 | +36: | ||
6909 | +37: GETSEC | ||
6910 | +38: escape # 3-byte escape 1 | ||
6911 | +39: | ||
6912 | +3a: escape # 3-byte escape 2 | ||
6913 | +3b: | ||
6914 | +3c: | ||
6915 | +3d: | ||
6916 | +3e: | ||
6917 | +3f: | ||
6918 | +# 0x0f 0x40-0x4f | ||
6919 | +40: CMOVO Gv,Ev | ||
6920 | +41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) | ||
6921 | +42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) | ||
6922 | +43: CMOVAE/NB/NC Gv,Ev | ||
6923 | +44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) | ||
6924 | +45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) | ||
6925 | +46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) | ||
6926 | +47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) | ||
6927 | +48: CMOVS Gv,Ev | ||
6928 | +49: CMOVNS Gv,Ev | ||
6929 | +4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) | ||
6930 | +4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk | ||
6931 | +4c: CMOVL/NGE Gv,Ev | ||
6932 | +4d: CMOVNL/GE Gv,Ev | ||
6933 | +4e: CMOVLE/NG Gv,Ev | ||
6934 | +4f: CMOVNLE/G Gv,Ev | ||
6935 | +# 0x0f 0x50-0x5f | ||
6936 | +50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) | ||
6937 | +51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) | ||
6938 | +52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) | ||
6939 | +53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) | ||
6940 | +54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) | ||
6941 | +55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) | ||
6942 | +56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) | ||
6943 | +57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) | ||
6944 | +58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) | ||
6945 | +59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) | ||
6946 | +5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) | ||
6947 | +5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) | ||
6948 | +5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) | ||
6949 | +5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) | ||
6950 | +5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) | ||
6951 | +5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) | ||
6952 | +# 0x0f 0x60-0x6f | ||
6953 | +60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) | ||
6954 | +61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) | ||
6955 | +62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) | ||
6956 | +63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) | ||
6957 | +64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) | ||
6958 | +65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) | ||
6959 | +66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) | ||
6960 | +67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) | ||
6961 | +68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) | ||
6962 | +69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) | ||
6963 | +6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) | ||
6964 | +6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) | ||
6965 | +6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) | ||
6966 | +6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) | ||
6967 | +6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) | ||
6968 | +6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqa32/64 Vx,Wx (66),(evo) | vmovdqu Vx,Wx (F3) | vmovdqu32/64 Vx,Wx (F3),(evo) | vmovdqu8/16 Vx,Wx (F2),(ev) | ||
6969 | +# 0x0f 0x70-0x7f | ||
6970 | +70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) | ||
6971 | +71: Grp12 (1A) | ||
6972 | +72: Grp13 (1A) | ||
6973 | +73: Grp14 (1A) | ||
6974 | +74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) | ||
6975 | +75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) | ||
6976 | +76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) | ||
6977 | +# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. | ||
6978 | +77: emms | vzeroupper | vzeroall | ||
6979 | +78: VMREAD Ey,Gy | vcvttps2udq/pd2udq Vx,Wpd (evo) | vcvttsd2usi Gv,Wx (F2),(ev) | vcvttss2usi Gv,Wx (F3),(ev) | vcvttps2uqq/pd2uqq Vx,Wx (66),(ev) | ||
6980 | +79: VMWRITE Gy,Ey | vcvtps2udq/pd2udq Vx,Wpd (evo) | vcvtsd2usi Gv,Wx (F2),(ev) | vcvtss2usi Gv,Wx (F3),(ev) | vcvtps2uqq/pd2uqq Vx,Wx (66),(ev) | ||
6981 | +7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) | ||
6982 | +7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) | ||
6983 | +7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) | ||
6984 | +7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) | ||
6985 | +7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) | ||
6986 | +7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev) | ||
6987 | +# 0x0f 0x80-0x8f | ||
6988 | +# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). | ||
6989 | +80: JO Jz (f64) | ||
6990 | +81: JNO Jz (f64) | ||
6991 | +82: JB/JC/JNAE Jz (f64) | ||
6992 | +83: JAE/JNB/JNC Jz (f64) | ||
6993 | +84: JE/JZ Jz (f64) | ||
6994 | +85: JNE/JNZ Jz (f64) | ||
6995 | +86: JBE/JNA Jz (f64) | ||
6996 | +87: JA/JNBE Jz (f64) | ||
6997 | +88: JS Jz (f64) | ||
6998 | +89: JNS Jz (f64) | ||
6999 | +8a: JP/JPE Jz (f64) | ||
7000 | +8b: JNP/JPO Jz (f64) | ||
7001 | +8c: JL/JNGE Jz (f64) | ||
7002 | +8d: JNL/JGE Jz (f64) | ||
7003 | +8e: JLE/JNG Jz (f64) | ||
7004 | +8f: JNLE/JG Jz (f64) | ||
7005 | +# 0x0f 0x90-0x9f | ||
7006 | +90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) | ||
7007 | +91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) | ||
7008 | +92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) | ||
7009 | +93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) | ||
7010 | +94: SETE/Z Eb | ||
7011 | +95: SETNE/NZ Eb | ||
7012 | +96: SETBE/NA Eb | ||
7013 | +97: SETA/NBE Eb | ||
7014 | +98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) | ||
7015 | +99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) | ||
7016 | +9a: SETP/PE Eb | ||
7017 | +9b: SETNP/PO Eb | ||
7018 | +9c: SETL/NGE Eb | ||
7019 | +9d: SETNL/GE Eb | ||
7020 | +9e: SETLE/NG Eb | ||
7021 | +9f: SETNLE/G Eb | ||
7022 | +# 0x0f 0xa0-0xaf | ||
7023 | +a0: PUSH FS (d64) | ||
7024 | +a1: POP FS (d64) | ||
7025 | +a2: CPUID | ||
7026 | +a3: BT Ev,Gv | ||
7027 | +a4: SHLD Ev,Gv,Ib | ||
7028 | +a5: SHLD Ev,Gv,CL | ||
7029 | +a6: GrpPDLK | ||
7030 | +a7: GrpRNG | ||
7031 | +a8: PUSH GS (d64) | ||
7032 | +a9: POP GS (d64) | ||
7033 | +aa: RSM | ||
7034 | +ab: BTS Ev,Gv | ||
7035 | +ac: SHRD Ev,Gv,Ib | ||
7036 | +ad: SHRD Ev,Gv,CL | ||
7037 | +ae: Grp15 (1A),(1C) | ||
7038 | +af: IMUL Gv,Ev | ||
7039 | +# 0x0f 0xb0-0xbf | ||
7040 | +b0: CMPXCHG Eb,Gb | ||
7041 | +b1: CMPXCHG Ev,Gv | ||
7042 | +b2: LSS Gv,Mp | ||
7043 | +b3: BTR Ev,Gv | ||
7044 | +b4: LFS Gv,Mp | ||
7045 | +b5: LGS Gv,Mp | ||
7046 | +b6: MOVZX Gv,Eb | ||
7047 | +b7: MOVZX Gv,Ew | ||
7048 | +b8: JMPE (!F3) | POPCNT Gv,Ev (F3) | ||
7049 | +b9: Grp10 (1A) | ||
7050 | +ba: Grp8 Ev,Ib (1A) | ||
7051 | +bb: BTC Ev,Gv | ||
7052 | +bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) | ||
7053 | +bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) | ||
7054 | +be: MOVSX Gv,Eb | ||
7055 | +bf: MOVSX Gv,Ew | ||
7056 | +# 0x0f 0xc0-0xcf | ||
7057 | +c0: XADD Eb,Gb | ||
7058 | +c1: XADD Ev,Gv | ||
7059 | +c2: vcmpps Vps,Hps,Wps,Ib | vcmppd Vpd,Hpd,Wpd,Ib (66) | vcmpss Vss,Hss,Wss,Ib (F3),(v1) | vcmpsd Vsd,Hsd,Wsd,Ib (F2),(v1) | ||
7060 | +c3: movnti My,Gy | ||
7061 | +c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) | ||
7062 | +c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) | ||
7063 | +c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) | ||
7064 | +c7: Grp9 (1A) | ||
7065 | +c8: BSWAP RAX/EAX/R8/R8D | ||
7066 | +c9: BSWAP RCX/ECX/R9/R9D | ||
7067 | +ca: BSWAP RDX/EDX/R10/R10D | ||
7068 | +cb: BSWAP RBX/EBX/R11/R11D | ||
7069 | +cc: BSWAP RSP/ESP/R12/R12D | ||
7070 | +cd: BSWAP RBP/EBP/R13/R13D | ||
7071 | +ce: BSWAP RSI/ESI/R14/R14D | ||
7072 | +cf: BSWAP RDI/EDI/R15/R15D | ||
7073 | +# 0x0f 0xd0-0xdf | ||
7074 | +d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) | ||
7075 | +d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) | ||
7076 | +d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) | ||
7077 | +d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) | ||
7078 | +d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) | ||
7079 | +d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) | ||
7080 | +d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) | ||
7081 | +d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) | ||
7082 | +d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) | ||
7083 | +d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) | ||
7084 | +da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) | ||
7085 | +db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) | ||
7086 | +dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) | ||
7087 | +dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) | ||
7088 | +de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) | ||
7089 | +df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) | ||
7090 | +# 0x0f 0xe0-0xef | ||
7091 | +e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) | ||
7092 | +e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) | ||
7093 | +e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) | ||
7094 | +e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) | ||
7095 | +e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) | ||
7096 | +e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) | ||
7097 | +e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) | ||
7098 | +e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) | ||
7099 | +e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) | ||
7100 | +e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) | ||
7101 | +ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) | ||
7102 | +eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) | ||
7103 | +ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) | ||
7104 | +ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) | ||
7105 | +ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) | ||
7106 | +ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) | ||
7107 | +# 0x0f 0xf0-0xff | ||
7108 | +f0: vlddqu Vx,Mx (F2) | ||
7109 | +f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) | ||
7110 | +f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) | ||
7111 | +f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) | ||
7112 | +f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) | ||
7113 | +f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) | ||
7114 | +f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) | ||
7115 | +f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) | ||
7116 | +f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) | ||
7117 | +f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) | ||
7118 | +fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) | ||
7119 | +fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) | ||
7120 | +fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) | ||
7121 | +fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) | ||
7122 | +fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) | ||
7123 | +ff: | ||
7124 | +EndTable | ||
7125 | + | ||
7126 | +Table: 3-byte opcode 1 (0x0f 0x38) | ||
7127 | +Referrer: 3-byte escape 1 | ||
7128 | +AVXcode: 2 | ||
7129 | +# 0x0f 0x38 0x00-0x0f | ||
7130 | +00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) | ||
7131 | +01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) | ||
7132 | +02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) | ||
7133 | +03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) | ||
7134 | +04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) | ||
7135 | +05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) | ||
7136 | +06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) | ||
7137 | +07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) | ||
7138 | +08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) | ||
7139 | +09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) | ||
7140 | +0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) | ||
7141 | +0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) | ||
7142 | +0c: vpermilps Vx,Hx,Wx (66),(v) | ||
7143 | +0d: vpermilpd Vx,Hx,Wx (66),(v) | ||
7144 | +0e: vtestps Vx,Wx (66),(v) | ||
7145 | +0f: vtestpd Vx,Wx (66),(v) | ||
7146 | +# 0x0f 0x38 0x10-0x1f | ||
7147 | +10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) | ||
7148 | +11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) | ||
7149 | +12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) | ||
7150 | +13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) | ||
7151 | +14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) | ||
7152 | +15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) | ||
7153 | +16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) | ||
7154 | +17: vptest Vx,Wx (66) | ||
7155 | +18: vbroadcastss Vx,Wd (66),(v) | ||
7156 | +19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) | ||
7157 | +1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) | ||
7158 | +1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) | ||
7159 | +1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) | ||
7160 | +1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) | ||
7161 | +1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) | ||
7162 | +1f: vpabsq Vx,Wx (66),(ev) | ||
7163 | +# 0x0f 0x38 0x20-0x2f | ||
7164 | +20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) | ||
7165 | +21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) | ||
7166 | +22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) | ||
7167 | +23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) | ||
7168 | +24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) | ||
7169 | +25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) | ||
7170 | +26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) | ||
7171 | +27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) | ||
7172 | +28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) | ||
7173 | +29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) | ||
7174 | +2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) | ||
7175 | +2b: vpackusdw Vx,Hx,Wx (66),(v1) | ||
7176 | +2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) | ||
7177 | +2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) | ||
7178 | +2e: vmaskmovps Mx,Hx,Vx (66),(v) | ||
7179 | +2f: vmaskmovpd Mx,Hx,Vx (66),(v) | ||
7180 | +# 0x0f 0x38 0x30-0x3f | ||
7181 | +30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) | ||
7182 | +31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) | ||
7183 | +32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) | ||
7184 | +33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) | ||
7185 | +34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) | ||
7186 | +35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) | ||
7187 | +36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) | ||
7188 | +37: vpcmpgtq Vx,Hx,Wx (66),(v1) | ||
7189 | +38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) | ||
7190 | +39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) | ||
7191 | +3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) | ||
7192 | +3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) | ||
7193 | +3c: vpmaxsb Vx,Hx,Wx (66),(v1) | ||
7194 | +3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) | ||
7195 | +3e: vpmaxuw Vx,Hx,Wx (66),(v1) | ||
7196 | +3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) | ||
7197 | +# 0x0f 0x38 0x40-0x8f | ||
7198 | +40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) | ||
7199 | +41: vphminposuw Vdq,Wdq (66),(v1) | ||
7200 | +42: vgetexpps/d Vx,Wx (66),(ev) | ||
7201 | +43: vgetexpss/d Vx,Hx,Wx (66),(ev) | ||
7202 | +44: vplzcntd/q Vx,Wx (66),(ev) | ||
7203 | +45: vpsrlvd/q Vx,Hx,Wx (66),(v) | ||
7204 | +46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) | ||
7205 | +47: vpsllvd/q Vx,Hx,Wx (66),(v) | ||
7206 | +# Skip 0x48-0x4b | ||
7207 | +4c: vrcp14ps/d Vpd,Wpd (66),(ev) | ||
7208 | +4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) | ||
7209 | +4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) | ||
7210 | +4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) | ||
7211 | +# Skip 0x50-0x57 | ||
7212 | +58: vpbroadcastd Vx,Wx (66),(v) | ||
7213 | +59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) | ||
7214 | +5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) | ||
7215 | +5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) | ||
7216 | +# Skip 0x5c-0x63 | ||
7217 | +64: vpblendmd/q Vx,Hx,Wx (66),(ev) | ||
7218 | +65: vblendmps/d Vx,Hx,Wx (66),(ev) | ||
7219 | +66: vpblendmb/w Vx,Hx,Wx (66),(ev) | ||
7220 | +# Skip 0x67-0x74 | ||
7221 | +75: vpermi2b/w Vx,Hx,Wx (66),(ev) | ||
7222 | +76: vpermi2d/q Vx,Hx,Wx (66),(ev) | ||
7223 | +77: vpermi2ps/d Vx,Hx,Wx (66),(ev) | ||
7224 | +78: vpbroadcastb Vx,Wx (66),(v) | ||
7225 | +79: vpbroadcastw Vx,Wx (66),(v) | ||
7226 | +7a: vpbroadcastb Vx,Rv (66),(ev) | ||
7227 | +7b: vpbroadcastw Vx,Rv (66),(ev) | ||
7228 | +7c: vpbroadcastd/q Vx,Rv (66),(ev) | ||
7229 | +7d: vpermt2b/w Vx,Hx,Wx (66),(ev) | ||
7230 | +7e: vpermt2d/q Vx,Hx,Wx (66),(ev) | ||
7231 | +7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) | ||
7232 | +80: INVEPT Gy,Mdq (66) | ||
7233 | +81: INVPID Gy,Mdq (66) | ||
7234 | +82: INVPCID Gy,Mdq (66) | ||
7235 | +83: vpmultishiftqb Vx,Hx,Wx (66),(ev) | ||
7236 | +88: vexpandps/d Vpd,Wpd (66),(ev) | ||
7237 | +89: vpexpandd/q Vx,Wx (66),(ev) | ||
7238 | +8a: vcompressps/d Wx,Vx (66),(ev) | ||
7239 | +8b: vpcompressd/q Wx,Vx (66),(ev) | ||
7240 | +8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) | ||
7241 | +8d: vpermb/w Vx,Hx,Wx (66),(ev) | ||
7242 | +8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) | ||
7243 | +# 0x0f 0x38 0x90-0xbf (FMA) | ||
7244 | +90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) | ||
7245 | +91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) | ||
7246 | +92: vgatherdps/d Vx,Hx,Wx (66),(v) | ||
7247 | +93: vgatherqps/d Vx,Hx,Wx (66),(v) | ||
7248 | +94: | ||
7249 | +95: | ||
7250 | +96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) | ||
7251 | +97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) | ||
7252 | +98: vfmadd132ps/d Vx,Hx,Wx (66),(v) | ||
7253 | +99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7254 | +9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) | ||
7255 | +9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7256 | +9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) | ||
7257 | +9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7258 | +9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) | ||
7259 | +9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7260 | +a0: vpscatterdd/q Wx,Vx (66),(ev) | ||
7261 | +a1: vpscatterqd/q Wx,Vx (66),(ev) | ||
7262 | +a2: vscatterdps/d Wx,Vx (66),(ev) | ||
7263 | +a3: vscatterqps/d Wx,Vx (66),(ev) | ||
7264 | +a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) | ||
7265 | +a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) | ||
7266 | +a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) | ||
7267 | +a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7268 | +aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) | ||
7269 | +ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7270 | +ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) | ||
7271 | +ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7272 | +ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) | ||
7273 | +af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7274 | +b4: vpmadd52luq Vx,Hx,Wx (66),(ev) | ||
7275 | +b5: vpmadd52huq Vx,Hx,Wx (66),(ev) | ||
7276 | +b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) | ||
7277 | +b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) | ||
7278 | +b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) | ||
7279 | +b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7280 | +ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) | ||
7281 | +bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7282 | +bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) | ||
7283 | +bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7284 | +be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) | ||
7285 | +bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) | ||
7286 | +# 0x0f 0x38 0xc0-0xff | ||
7287 | +c4: vpconflictd/q Vx,Wx (66),(ev) | ||
7288 | +c6: Grp18 (1A) | ||
7289 | +c7: Grp19 (1A) | ||
7290 | +c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) | ||
7291 | +c9: sha1msg1 Vdq,Wdq | ||
7292 | +ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) | ||
7293 | +cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) | ||
7294 | +cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) | ||
7295 | +cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) | ||
7296 | +db: VAESIMC Vdq,Wdq (66),(v1) | ||
7297 | +dc: VAESENC Vdq,Hdq,Wdq (66),(v1) | ||
7298 | +dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) | ||
7299 | +de: VAESDEC Vdq,Hdq,Wdq (66),(v1) | ||
7300 | +df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) | ||
7301 | +f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) | ||
7302 | +f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) | ||
7303 | +f2: ANDN Gy,By,Ey (v) | ||
7304 | +f3: Grp17 (1A) | ||
7305 | +f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) | ||
7306 | +f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) | ||
7307 | +f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) | ||
7308 | +EndTable | ||
7309 | + | ||
7310 | +Table: 3-byte opcode 2 (0x0f 0x3a) | ||
7311 | +Referrer: 3-byte escape 2 | ||
7312 | +AVXcode: 3 | ||
7313 | +# 0x0f 0x3a 0x00-0xff | ||
7314 | +00: vpermq Vqq,Wqq,Ib (66),(v) | ||
7315 | +01: vpermpd Vqq,Wqq,Ib (66),(v) | ||
7316 | +02: vpblendd Vx,Hx,Wx,Ib (66),(v) | ||
7317 | +03: valignd/q Vx,Hx,Wx,Ib (66),(ev) | ||
7318 | +04: vpermilps Vx,Wx,Ib (66),(v) | ||
7319 | +05: vpermilpd Vx,Wx,Ib (66),(v) | ||
7320 | +06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) | ||
7321 | +07: | ||
7322 | +08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) | ||
7323 | +09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) | ||
7324 | +0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) | ||
7325 | +0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) | ||
7326 | +0c: vblendps Vx,Hx,Wx,Ib (66) | ||
7327 | +0d: vblendpd Vx,Hx,Wx,Ib (66) | ||
7328 | +0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) | ||
7329 | +0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) | ||
7330 | +14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) | ||
7331 | +15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) | ||
7332 | +16: vpextrd/q Ey,Vdq,Ib (66),(v1) | ||
7333 | +17: vextractps Ed,Vdq,Ib (66),(v1) | ||
7334 | +18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) | ||
7335 | +19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) | ||
7336 | +1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) | ||
7337 | +1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) | ||
7338 | +1d: vcvtps2ph Wx,Vx,Ib (66),(v) | ||
7339 | +1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) | ||
7340 | +1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) | ||
7341 | +20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) | ||
7342 | +21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) | ||
7343 | +22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) | ||
7344 | +23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) | ||
7345 | +25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) | ||
7346 | +26: vgetmantps/d Vx,Wx,Ib (66),(ev) | ||
7347 | +27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) | ||
7348 | +30: kshiftrb/w Vk,Uk,Ib (66),(v) | ||
7349 | +31: kshiftrd/q Vk,Uk,Ib (66),(v) | ||
7350 | +32: kshiftlb/w Vk,Uk,Ib (66),(v) | ||
7351 | +33: kshiftld/q Vk,Uk,Ib (66),(v) | ||
7352 | +38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) | ||
7353 | +39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) | ||
7354 | +3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) | ||
7355 | +3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) | ||
7356 | +3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) | ||
7357 | +3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) | ||
7358 | +40: vdpps Vx,Hx,Wx,Ib (66) | ||
7359 | +41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) | ||
7360 | +42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) | ||
7361 | +43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) | ||
7362 | +44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) | ||
7363 | +46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) | ||
7364 | +4a: vblendvps Vx,Hx,Wx,Lx (66),(v) | ||
7365 | +4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) | ||
7366 | +4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) | ||
7367 | +50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) | ||
7368 | +51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) | ||
7369 | +54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) | ||
7370 | +55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) | ||
7371 | +56: vreduceps/d Vx,Wx,Ib (66),(ev) | ||
7372 | +57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) | ||
7373 | +60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) | ||
7374 | +61: vpcmpestri Vdq,Wdq,Ib (66),(v1) | ||
7375 | +62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) | ||
7376 | +63: vpcmpistri Vdq,Wdq,Ib (66),(v1) | ||
7377 | +66: vfpclassps/d Vk,Wx,Ib (66),(ev) | ||
7378 | +67: vfpclassss/d Vk,Wx,Ib (66),(ev) | ||
7379 | +cc: sha1rnds4 Vdq,Wdq,Ib | ||
7380 | +df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) | ||
7381 | +f0: RORX Gy,Ey,Ib (F2),(v) | ||
7382 | +EndTable | ||
7383 | + | ||
7384 | +GrpTable: Grp1 | ||
7385 | +0: ADD | ||
7386 | +1: OR | ||
7387 | +2: ADC | ||
7388 | +3: SBB | ||
7389 | +4: AND | ||
7390 | +5: SUB | ||
7391 | +6: XOR | ||
7392 | +7: CMP | ||
7393 | +EndTable | ||
7394 | + | ||
7395 | +GrpTable: Grp1A | ||
7396 | +0: POP | ||
7397 | +EndTable | ||
7398 | + | ||
7399 | +GrpTable: Grp2 | ||
7400 | +0: ROL | ||
7401 | +1: ROR | ||
7402 | +2: RCL | ||
7403 | +3: RCR | ||
7404 | +4: SHL/SAL | ||
7405 | +5: SHR | ||
7406 | +6: | ||
7407 | +7: SAR | ||
7408 | +EndTable | ||
7409 | + | ||
7410 | +GrpTable: Grp3_1 | ||
7411 | +0: TEST Eb,Ib | ||
7412 | +1: TEST Eb,Ib | ||
7413 | +2: NOT Eb | ||
7414 | +3: NEG Eb | ||
7415 | +4: MUL AL,Eb | ||
7416 | +5: IMUL AL,Eb | ||
7417 | +6: DIV AL,Eb | ||
7418 | +7: IDIV AL,Eb | ||
7419 | +EndTable | ||
7420 | + | ||
7421 | +GrpTable: Grp3_2 | ||
7422 | +0: TEST Ev,Iz | ||
7423 | +1: | ||
7424 | +2: NOT Ev | ||
7425 | +3: NEG Ev | ||
7426 | +4: MUL rAX,Ev | ||
7427 | +5: IMUL rAX,Ev | ||
7428 | +6: DIV rAX,Ev | ||
7429 | +7: IDIV rAX,Ev | ||
7430 | +EndTable | ||
7431 | + | ||
7432 | +GrpTable: Grp4 | ||
7433 | +0: INC Eb | ||
7434 | +1: DEC Eb | ||
7435 | +EndTable | ||
7436 | + | ||
7437 | +GrpTable: Grp5 | ||
7438 | +0: INC Ev | ||
7439 | +1: DEC Ev | ||
7440 | +# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). | ||
7441 | +2: CALLN Ev (f64) | ||
7442 | +3: CALLF Ep | ||
7443 | +4: JMPN Ev (f64) | ||
7444 | +5: JMPF Mp | ||
7445 | +6: PUSH Ev (d64) | ||
7446 | +7: | ||
7447 | +EndTable | ||
7448 | + | ||
7449 | +GrpTable: Grp6 | ||
7450 | +0: SLDT Rv/Mw | ||
7451 | +1: STR Rv/Mw | ||
7452 | +2: LLDT Ew | ||
7453 | +3: LTR Ew | ||
7454 | +4: VERR Ew | ||
7455 | +5: VERW Ew | ||
7456 | +EndTable | ||
7457 | + | ||
7458 | +GrpTable: Grp7 | ||
7459 | +0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | ||
7460 | +1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) | ||
7461 | +2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) | ||
7462 | +3: LIDT Ms | ||
7463 | +4: SMSW Mw/Rv | ||
7464 | +5: rdpkru (110),(11B) | wrpkru (111),(11B) | ||
7465 | +6: LMSW Ew | ||
7466 | +7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) | ||
7467 | +EndTable | ||
7468 | + | ||
7469 | +GrpTable: Grp8 | ||
7470 | +4: BT | ||
7471 | +5: BTS | ||
7472 | +6: BTR | ||
7473 | +7: BTC | ||
7474 | +EndTable | ||
7475 | + | ||
7476 | +GrpTable: Grp9 | ||
7477 | +1: CMPXCHG8B/16B Mq/Mdq | ||
7478 | +3: xrstors | ||
7479 | +4: xsavec | ||
7480 | +5: xsaves | ||
7481 | +6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) | ||
7482 | +7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) | ||
7483 | +EndTable | ||
7484 | + | ||
7485 | +GrpTable: Grp10 | ||
7486 | +EndTable | ||
7487 | + | ||
7488 | +# Grp11A and Grp11B are expressed as Grp11 in Intel SDM | ||
7489 | +GrpTable: Grp11A | ||
7490 | +0: MOV Eb,Ib | ||
7491 | +7: XABORT Ib (000),(11B) | ||
7492 | +EndTable | ||
7493 | + | ||
7494 | +GrpTable: Grp11B | ||
7495 | +0: MOV Eb,Iz | ||
7496 | +7: XBEGIN Jz (000),(11B) | ||
7497 | +EndTable | ||
7498 | + | ||
7499 | +GrpTable: Grp12 | ||
7500 | +2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) | ||
7501 | +4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) | ||
7502 | +6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) | ||
7503 | +EndTable | ||
7504 | + | ||
7505 | +GrpTable: Grp13 | ||
7506 | +0: vprord/q Hx,Wx,Ib (66),(ev) | ||
7507 | +1: vprold/q Hx,Wx,Ib (66),(ev) | ||
7508 | +2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) | ||
7509 | +4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) | ||
7510 | +6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) | ||
7511 | +EndTable | ||
7512 | + | ||
7513 | +GrpTable: Grp14 | ||
7514 | +2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) | ||
7515 | +3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) | ||
7516 | +6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) | ||
7517 | +7: vpslldq Hx,Ux,Ib (66),(11B),(v1) | ||
7518 | +EndTable | ||
7519 | + | ||
7520 | +GrpTable: Grp15 | ||
7521 | +0: fxsave | RDFSBASE Ry (F3),(11B) | ||
7522 | +1: fxstor | RDGSBASE Ry (F3),(11B) | ||
7523 | +2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) | ||
7524 | +3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) | ||
7525 | +4: XSAVE | ||
7526 | +5: XRSTOR | lfence (11B) | ||
7527 | +6: XSAVEOPT | clwb (66) | mfence (11B) | ||
7528 | +7: clflush | clflushopt (66) | sfence (11B) | ||
7529 | +EndTable | ||
7530 | + | ||
7531 | +GrpTable: Grp16 | ||
7532 | +0: prefetch NTA | ||
7533 | +1: prefetch T0 | ||
7534 | +2: prefetch T1 | ||
7535 | +3: prefetch T2 | ||
7536 | +EndTable | ||
7537 | + | ||
7538 | +GrpTable: Grp17 | ||
7539 | +1: BLSR By,Ey (v) | ||
7540 | +2: BLSMSK By,Ey (v) | ||
7541 | +3: BLSI By,Ey (v) | ||
7542 | +EndTable | ||
7543 | + | ||
7544 | +GrpTable: Grp18 | ||
7545 | +1: vgatherpf0dps/d Wx (66),(ev) | ||
7546 | +2: vgatherpf1dps/d Wx (66),(ev) | ||
7547 | +5: vscatterpf0dps/d Wx (66),(ev) | ||
7548 | +6: vscatterpf1dps/d Wx (66),(ev) | ||
7549 | +EndTable | ||
7550 | + | ||
7551 | +GrpTable: Grp19 | ||
7552 | +1: vgatherpf0qps/d Wx (66),(ev) | ||
7553 | +2: vgatherpf1qps/d Wx (66),(ev) | ||
7554 | +5: vscatterpf0qps/d Wx (66),(ev) | ||
7555 | +6: vscatterpf1qps/d Wx (66),(ev) | ||
7556 | +EndTable | ||
7557 | + | ||
7558 | +# AMD's Prefetch Group | ||
7559 | +GrpTable: GrpP | ||
7560 | +0: PREFETCH | ||
7561 | +1: PREFETCHW | ||
7562 | +EndTable | ||
7563 | + | ||
7564 | +GrpTable: GrpPDLK | ||
7565 | +0: MONTMUL | ||
7566 | +1: XSHA1 | ||
7567 | +2: XSHA2 | ||
7568 | +EndTable | ||
7569 | + | ||
7570 | +GrpTable: GrpRNG | ||
7571 | +0: xstore-rng | ||
7572 | +1: xcrypt-ecb | ||
7573 | +2: xcrypt-cbc | ||
7574 | +4: xcrypt-cfb | ||
7575 | +5: xcrypt-ofb | ||
7576 | +EndTable | ||
7577 | diff --git a/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk | ||
7578 | new file mode 100644 | ||
7579 | index 000000000000..a3d2c62fd805 | ||
7580 | --- /dev/null | ||
7581 | +++ b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk | ||
7582 | @@ -0,0 +1,392 @@ | ||
7583 | +#!/bin/awk -f | ||
7584 | +# gen-insn-attr-x86.awk: Instruction attribute table generator | ||
7585 | +# Written by Masami Hiramatsu <mhiramat@redhat.com> | ||
7586 | +# | ||
7587 | +# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c | ||
7588 | + | ||
7589 | +# Awk implementation sanity check | ||
7590 | +function check_awk_implement() { | ||
7591 | + if (sprintf("%x", 0) != "0") | ||
7592 | + return "Your awk has a printf-format problem." | ||
7593 | + return "" | ||
7594 | +} | ||
7595 | + | ||
7596 | +# Clear working vars | ||
7597 | +function clear_vars() { | ||
7598 | + delete table | ||
7599 | + delete lptable2 | ||
7600 | + delete lptable1 | ||
7601 | + delete lptable3 | ||
7602 | + eid = -1 # escape id | ||
7603 | + gid = -1 # group id | ||
7604 | + aid = -1 # AVX id | ||
7605 | + tname = "" | ||
7606 | +} | ||
7607 | + | ||
7608 | +BEGIN { | ||
7609 | + # Implementation error checking | ||
7610 | + awkchecked = check_awk_implement() | ||
7611 | + if (awkchecked != "") { | ||
7612 | + print "Error: " awkchecked > "/dev/stderr" | ||
7613 | + print "Please try to use gawk." > "/dev/stderr" | ||
7614 | + exit 1 | ||
7615 | + } | ||
7616 | + | ||
7617 | + # Setup generating tables | ||
7618 | + print "/* x86 opcode map generated from x86-opcode-map.txt */" | ||
7619 | + print "/* Do not change this code. */\n" | ||
7620 | + ggid = 1 | ||
7621 | + geid = 1 | ||
7622 | + gaid = 0 | ||
7623 | + delete etable | ||
7624 | + delete gtable | ||
7625 | + delete atable | ||
7626 | + | ||
7627 | + opnd_expr = "^[A-Za-z/]" | ||
7628 | + ext_expr = "^\\(" | ||
7629 | + sep_expr = "^\\|$" | ||
7630 | + group_expr = "^Grp[0-9A-Za-z]+" | ||
7631 | + | ||
7632 | + imm_expr = "^[IJAOL][a-z]" | ||
7633 | + imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" | ||
7634 | + imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" | ||
7635 | + imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" | ||
7636 | + imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" | ||
7637 | + imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" | ||
7638 | + imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" | ||
7639 | + imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" | ||
7640 | + imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" | ||
7641 | + imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" | ||
7642 | + imm_flag["Ob"] = "INAT_MOFFSET" | ||
7643 | + imm_flag["Ov"] = "INAT_MOFFSET" | ||
7644 | + imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" | ||
7645 | + | ||
7646 | + modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" | ||
7647 | + force64_expr = "\\([df]64\\)" | ||
7648 | + rex_expr = "^REX(\\.[XRWB]+)*" | ||
7649 | + fpu_expr = "^ESC" # TODO | ||
7650 | + | ||
7651 | + lprefix1_expr = "\\((66|!F3)\\)" | ||
7652 | + lprefix2_expr = "\\(F3\\)" | ||
7653 | + lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)" | ||
7654 | + lprefix_expr = "\\((66|F2|F3)\\)" | ||
7655 | + max_lprefix = 4 | ||
7656 | + | ||
7657 | + # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript | ||
7658 | + # accepts VEX prefix | ||
7659 | + vexok_opcode_expr = "^[vk].*" | ||
7660 | + vexok_expr = "\\(v1\\)" | ||
7661 | + # All opcodes with (v) superscript supports *only* VEX prefix | ||
7662 | + vexonly_expr = "\\(v\\)" | ||
7663 | + # All opcodes with (ev) superscript supports *only* EVEX prefix | ||
7664 | + evexonly_expr = "\\(ev\\)" | ||
7665 | + | ||
7666 | + prefix_expr = "\\(Prefix\\)" | ||
7667 | + prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" | ||
7668 | + prefix_num["REPNE"] = "INAT_PFX_REPNE" | ||
7669 | + prefix_num["REP/REPE"] = "INAT_PFX_REPE" | ||
7670 | + prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" | ||
7671 | + prefix_num["XRELEASE"] = "INAT_PFX_REPE" | ||
7672 | + prefix_num["LOCK"] = "INAT_PFX_LOCK" | ||
7673 | + prefix_num["SEG=CS"] = "INAT_PFX_CS" | ||
7674 | + prefix_num["SEG=DS"] = "INAT_PFX_DS" | ||
7675 | + prefix_num["SEG=ES"] = "INAT_PFX_ES" | ||
7676 | + prefix_num["SEG=FS"] = "INAT_PFX_FS" | ||
7677 | + prefix_num["SEG=GS"] = "INAT_PFX_GS" | ||
7678 | + prefix_num["SEG=SS"] = "INAT_PFX_SS" | ||
7679 | + prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" | ||
7680 | + prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" | ||
7681 | + prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" | ||
7682 | + prefix_num["EVEX"] = "INAT_PFX_EVEX" | ||
7683 | + | ||
7684 | + clear_vars() | ||
7685 | +} | ||
7686 | + | ||
7687 | +function semantic_error(msg) { | ||
7688 | + print "Semantic error at " NR ": " msg > "/dev/stderr" | ||
7689 | + exit 1 | ||
7690 | +} | ||
7691 | + | ||
7692 | +function debug(msg) { | ||
7693 | + print "DEBUG: " msg | ||
7694 | +} | ||
7695 | + | ||
7696 | +function array_size(arr, i,c) { | ||
7697 | + c = 0 | ||
7698 | + for (i in arr) | ||
7699 | + c++ | ||
7700 | + return c | ||
7701 | +} | ||
7702 | + | ||
7703 | +/^Table:/ { | ||
7704 | + print "/* " $0 " */" | ||
7705 | + if (tname != "") | ||
7706 | + semantic_error("Hit Table: before EndTable:."); | ||
7707 | +} | ||
7708 | + | ||
7709 | +/^Referrer:/ { | ||
7710 | + if (NF != 1) { | ||
7711 | + # escape opcode table | ||
7712 | + ref = "" | ||
7713 | + for (i = 2; i <= NF; i++) | ||
7714 | + ref = ref $i | ||
7715 | + eid = escape[ref] | ||
7716 | + tname = sprintf("inat_escape_table_%d", eid) | ||
7717 | + } | ||
7718 | +} | ||
7719 | + | ||
7720 | +/^AVXcode:/ { | ||
7721 | + if (NF != 1) { | ||
7722 | + # AVX/escape opcode table | ||
7723 | + aid = $2 | ||
7724 | + if (gaid <= aid) | ||
7725 | + gaid = aid + 1 | ||
7726 | + if (tname == "") # AVX only opcode table | ||
7727 | + tname = sprintf("inat_avx_table_%d", $2) | ||
7728 | + } | ||
7729 | + if (aid == -1 && eid == -1) # primary opcode table | ||
7730 | + tname = "inat_primary_table" | ||
7731 | +} | ||
7732 | + | ||
7733 | +/^GrpTable:/ { | ||
7734 | + print "/* " $0 " */" | ||
7735 | + if (!($2 in group)) | ||
7736 | + semantic_error("No group: " $2 ) | ||
7737 | + gid = group[$2] | ||
7738 | + tname = "inat_group_table_" gid | ||
7739 | +} | ||
7740 | + | ||
7741 | +function print_table(tbl,name,fmt,n) | ||
7742 | +{ | ||
7743 | + print "const insn_attr_t " name " = {" | ||
7744 | + for (i = 0; i < n; i++) { | ||
7745 | + id = sprintf(fmt, i) | ||
7746 | + if (tbl[id]) | ||
7747 | + print " [" id "] = " tbl[id] "," | ||
7748 | + } | ||
7749 | + print "};" | ||
7750 | +} | ||
7751 | + | ||
7752 | +/^EndTable/ { | ||
7753 | + if (gid != -1) { | ||
7754 | + # print group tables | ||
7755 | + if (array_size(table) != 0) { | ||
7756 | + print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", | ||
7757 | + "0x%x", 8) | ||
7758 | + gtable[gid,0] = tname | ||
7759 | + } | ||
7760 | + if (array_size(lptable1) != 0) { | ||
7761 | + print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", | ||
7762 | + "0x%x", 8) | ||
7763 | + gtable[gid,1] = tname "_1" | ||
7764 | + } | ||
7765 | + if (array_size(lptable2) != 0) { | ||
7766 | + print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", | ||
7767 | + "0x%x", 8) | ||
7768 | + gtable[gid,2] = tname "_2" | ||
7769 | + } | ||
7770 | + if (array_size(lptable3) != 0) { | ||
7771 | + print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", | ||
7772 | + "0x%x", 8) | ||
7773 | + gtable[gid,3] = tname "_3" | ||
7774 | + } | ||
7775 | + } else { | ||
7776 | + # print primary/escaped tables | ||
7777 | + if (array_size(table) != 0) { | ||
7778 | + print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", | ||
7779 | + "0x%02x", 256) | ||
7780 | + etable[eid,0] = tname | ||
7781 | + if (aid >= 0) | ||
7782 | + atable[aid,0] = tname | ||
7783 | + } | ||
7784 | + if (array_size(lptable1) != 0) { | ||
7785 | + print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", | ||
7786 | + "0x%02x", 256) | ||
7787 | + etable[eid,1] = tname "_1" | ||
7788 | + if (aid >= 0) | ||
7789 | + atable[aid,1] = tname "_1" | ||
7790 | + } | ||
7791 | + if (array_size(lptable2) != 0) { | ||
7792 | + print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", | ||
7793 | + "0x%02x", 256) | ||
7794 | + etable[eid,2] = tname "_2" | ||
7795 | + if (aid >= 0) | ||
7796 | + atable[aid,2] = tname "_2" | ||
7797 | + } | ||
7798 | + if (array_size(lptable3) != 0) { | ||
7799 | + print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", | ||
7800 | + "0x%02x", 256) | ||
7801 | + etable[eid,3] = tname "_3" | ||
7802 | + if (aid >= 0) | ||
7803 | + atable[aid,3] = tname "_3" | ||
7804 | + } | ||
7805 | + } | ||
7806 | + print "" | ||
7807 | + clear_vars() | ||
7808 | +} | ||
7809 | + | ||
7810 | +function add_flags(old,new) { | ||
7811 | + if (old && new) | ||
7812 | + return old " | " new | ||
7813 | + else if (old) | ||
7814 | + return old | ||
7815 | + else | ||
7816 | + return new | ||
7817 | +} | ||
7818 | + | ||
7819 | +# convert operands to flags. | ||
7820 | +function convert_operands(count,opnd, i,j,imm,mod) | ||
7821 | +{ | ||
7822 | + imm = null | ||
7823 | + mod = null | ||
7824 | + for (j = 1; j <= count; j++) { | ||
7825 | + i = opnd[j] | ||
7826 | + if (match(i, imm_expr) == 1) { | ||
7827 | + if (!imm_flag[i]) | ||
7828 | + semantic_error("Unknown imm opnd: " i) | ||
7829 | + if (imm) { | ||
7830 | + if (i != "Ib") | ||
7831 | + semantic_error("Second IMM error") | ||
7832 | + imm = add_flags(imm, "INAT_SCNDIMM") | ||
7833 | + } else | ||
7834 | + imm = imm_flag[i] | ||
7835 | + } else if (match(i, modrm_expr)) | ||
7836 | + mod = "INAT_MODRM" | ||
7837 | + } | ||
7838 | + return add_flags(imm, mod) | ||
7839 | +} | ||
7840 | + | ||
7841 | +/^[0-9a-f]+\:/ { | ||
7842 | + if (NR == 1) | ||
7843 | + next | ||
7844 | + # get index | ||
7845 | + idx = "0x" substr($1, 1, index($1,":") - 1) | ||
7846 | + if (idx in table) | ||
7847 | + semantic_error("Redefine " idx " in " tname) | ||
7848 | + | ||
7849 | + # check if escaped opcode | ||
7850 | + if ("escape" == $2) { | ||
7851 | + if ($3 != "#") | ||
7852 | + semantic_error("No escaped name") | ||
7853 | + ref = "" | ||
7854 | + for (i = 4; i <= NF; i++) | ||
7855 | + ref = ref $i | ||
7856 | + if (ref in escape) | ||
7857 | + semantic_error("Redefine escape (" ref ")") | ||
7858 | + escape[ref] = geid | ||
7859 | + geid++ | ||
7860 | + table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" | ||
7861 | + next | ||
7862 | + } | ||
7863 | + | ||
7864 | + variant = null | ||
7865 | + # converts | ||
7866 | + i = 2 | ||
7867 | + while (i <= NF) { | ||
7868 | + opcode = $(i++) | ||
7869 | + delete opnds | ||
7870 | + ext = null | ||
7871 | + flags = null | ||
7872 | + opnd = null | ||
7873 | + # parse one opcode | ||
7874 | + if (match($i, opnd_expr)) { | ||
7875 | + opnd = $i | ||
7876 | + count = split($(i++), opnds, ",") | ||
7877 | + flags = convert_operands(count, opnds) | ||
7878 | + } | ||
7879 | + if (match($i, ext_expr)) | ||
7880 | + ext = $(i++) | ||
7881 | + if (match($i, sep_expr)) | ||
7882 | + i++ | ||
7883 | + else if (i < NF) | ||
7884 | + semantic_error($i " is not a separator") | ||
7885 | + | ||
7886 | + # check if group opcode | ||
7887 | + if (match(opcode, group_expr)) { | ||
7888 | + if (!(opcode in group)) { | ||
7889 | + group[opcode] = ggid | ||
7890 | + ggid++ | ||
7891 | + } | ||
7892 | + flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") | ||
7893 | + } | ||
7894 | + # check force(or default) 64bit | ||
7895 | + if (match(ext, force64_expr)) | ||
7896 | + flags = add_flags(flags, "INAT_FORCE64") | ||
7897 | + | ||
7898 | + # check REX prefix | ||
7899 | + if (match(opcode, rex_expr)) | ||
7900 | + flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") | ||
7901 | + | ||
7902 | + # check coprocessor escape : TODO | ||
7903 | + if (match(opcode, fpu_expr)) | ||
7904 | + flags = add_flags(flags, "INAT_MODRM") | ||
7905 | + | ||
7906 | + # check VEX codes | ||
7907 | + if (match(ext, evexonly_expr)) | ||
7908 | + flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") | ||
7909 | + else if (match(ext, vexonly_expr)) | ||
7910 | + flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") | ||
7911 | + else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) | ||
7912 | + flags = add_flags(flags, "INAT_VEXOK") | ||
7913 | + | ||
7914 | + # check prefixes | ||
7915 | + if (match(ext, prefix_expr)) { | ||
7916 | + if (!prefix_num[opcode]) | ||
7917 | + semantic_error("Unknown prefix: " opcode) | ||
7918 | + flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") | ||
7919 | + } | ||
7920 | + if (length(flags) == 0) | ||
7921 | + continue | ||
7922 | + # check if last prefix | ||
7923 | + if (match(ext, lprefix1_expr)) { | ||
7924 | + lptable1[idx] = add_flags(lptable1[idx],flags) | ||
7925 | + variant = "INAT_VARIANT" | ||
7926 | + } | ||
7927 | + if (match(ext, lprefix2_expr)) { | ||
7928 | + lptable2[idx] = add_flags(lptable2[idx],flags) | ||
7929 | + variant = "INAT_VARIANT" | ||
7930 | + } | ||
7931 | + if (match(ext, lprefix3_expr)) { | ||
7932 | + lptable3[idx] = add_flags(lptable3[idx],flags) | ||
7933 | + variant = "INAT_VARIANT" | ||
7934 | + } | ||
7935 | + if (!match(ext, lprefix_expr)){ | ||
7936 | + table[idx] = add_flags(table[idx],flags) | ||
7937 | + } | ||
7938 | + } | ||
7939 | + if (variant) | ||
7940 | + table[idx] = add_flags(table[idx],variant) | ||
7941 | +} | ||
7942 | + | ||
7943 | +END { | ||
7944 | + if (awkchecked != "") | ||
7945 | + exit 1 | ||
7946 | + # print escape opcode map's array | ||
7947 | + print "/* Escape opcode map array */" | ||
7948 | + print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ | ||
7949 | + "[INAT_LSTPFX_MAX + 1] = {" | ||
7950 | + for (i = 0; i < geid; i++) | ||
7951 | + for (j = 0; j < max_lprefix; j++) | ||
7952 | + if (etable[i,j]) | ||
7953 | + print " ["i"]["j"] = "etable[i,j]"," | ||
7954 | + print "};\n" | ||
7955 | + # print group opcode map's array | ||
7956 | + print "/* Group opcode map array */" | ||
7957 | + print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ | ||
7958 | + "[INAT_LSTPFX_MAX + 1] = {" | ||
7959 | + for (i = 0; i < ggid; i++) | ||
7960 | + for (j = 0; j < max_lprefix; j++) | ||
7961 | + if (gtable[i,j]) | ||
7962 | + print " ["i"]["j"] = "gtable[i,j]"," | ||
7963 | + print "};\n" | ||
7964 | + # print AVX opcode map's array | ||
7965 | + print "/* AVX opcode map array */" | ||
7966 | + print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ | ||
7967 | + "[INAT_LSTPFX_MAX + 1] = {" | ||
7968 | + for (i = 0; i < gaid; i++) | ||
7969 | + for (j = 0; j < max_lprefix; j++) | ||
7970 | + if (atable[i,j]) | ||
7971 | + print " ["i"]["j"] = "atable[i,j]"," | ||
7972 | + print "};" | ||
7973 | +} | ||
7974 | + | ||
7975 | diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c | ||
7976 | index a688a857a7ae..694abc628e9b 100644 | ||
7977 | --- a/tools/objtool/builtin-check.c | ||
7978 | +++ b/tools/objtool/builtin-check.c | ||
7979 | @@ -1,5 +1,5 @@ | ||
7980 | /* | ||
7981 | - * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> | ||
7982 | + * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
7983 | * | ||
7984 | * This program is free software; you can redistribute it and/or | ||
7985 | * modify it under the terms of the GNU General Public License | ||
7986 | @@ -25,1300 +25,35 @@ | ||
7987 | * For more information, see tools/objtool/Documentation/stack-validation.txt. | ||
7988 | */ | ||
7989 | |||
7990 | -#include <string.h> | ||
7991 | -#include <stdlib.h> | ||
7992 | #include <subcmd/parse-options.h> | ||
7993 | - | ||
7994 | #include "builtin.h" | ||
7995 | -#include "elf.h" | ||
7996 | -#include "special.h" | ||
7997 | -#include "arch.h" | ||
7998 | -#include "warn.h" | ||
7999 | - | ||
8000 | -#include <linux/hashtable.h> | ||
8001 | - | ||
8002 | -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
8003 | - | ||
8004 | -#define STATE_FP_SAVED 0x1 | ||
8005 | -#define STATE_FP_SETUP 0x2 | ||
8006 | -#define STATE_FENTRY 0x4 | ||
8007 | - | ||
8008 | -struct instruction { | ||
8009 | - struct list_head list; | ||
8010 | - struct hlist_node hash; | ||
8011 | - struct section *sec; | ||
8012 | - unsigned long offset; | ||
8013 | - unsigned int len, state; | ||
8014 | - unsigned char type; | ||
8015 | - unsigned long immediate; | ||
8016 | - bool alt_group, visited, ignore_alts; | ||
8017 | - struct symbol *call_dest; | ||
8018 | - struct instruction *jump_dest; | ||
8019 | - struct list_head alts; | ||
8020 | - struct symbol *func; | ||
8021 | -}; | ||
8022 | - | ||
8023 | -struct alternative { | ||
8024 | - struct list_head list; | ||
8025 | - struct instruction *insn; | ||
8026 | -}; | ||
8027 | - | ||
8028 | -struct objtool_file { | ||
8029 | - struct elf *elf; | ||
8030 | - struct list_head insn_list; | ||
8031 | - DECLARE_HASHTABLE(insn_hash, 16); | ||
8032 | - struct section *rodata, *whitelist; | ||
8033 | - bool ignore_unreachables, c_file; | ||
8034 | -}; | ||
8035 | - | ||
8036 | -const char *objname; | ||
8037 | -static bool nofp; | ||
8038 | - | ||
8039 | -static struct instruction *find_insn(struct objtool_file *file, | ||
8040 | - struct section *sec, unsigned long offset) | ||
8041 | -{ | ||
8042 | - struct instruction *insn; | ||
8043 | - | ||
8044 | - hash_for_each_possible(file->insn_hash, insn, hash, offset) | ||
8045 | - if (insn->sec == sec && insn->offset == offset) | ||
8046 | - return insn; | ||
8047 | - | ||
8048 | - return NULL; | ||
8049 | -} | ||
8050 | - | ||
8051 | -static struct instruction *next_insn_same_sec(struct objtool_file *file, | ||
8052 | - struct instruction *insn) | ||
8053 | -{ | ||
8054 | - struct instruction *next = list_next_entry(insn, list); | ||
8055 | - | ||
8056 | - if (&next->list == &file->insn_list || next->sec != insn->sec) | ||
8057 | - return NULL; | ||
8058 | - | ||
8059 | - return next; | ||
8060 | -} | ||
8061 | - | ||
8062 | -static bool gcov_enabled(struct objtool_file *file) | ||
8063 | -{ | ||
8064 | - struct section *sec; | ||
8065 | - struct symbol *sym; | ||
8066 | - | ||
8067 | - list_for_each_entry(sec, &file->elf->sections, list) | ||
8068 | - list_for_each_entry(sym, &sec->symbol_list, list) | ||
8069 | - if (!strncmp(sym->name, "__gcov_.", 8)) | ||
8070 | - return true; | ||
8071 | - | ||
8072 | - return false; | ||
8073 | -} | ||
8074 | - | ||
8075 | -#define for_each_insn(file, insn) \ | ||
8076 | - list_for_each_entry(insn, &file->insn_list, list) | ||
8077 | - | ||
8078 | -#define func_for_each_insn(file, func, insn) \ | ||
8079 | - for (insn = find_insn(file, func->sec, func->offset); \ | ||
8080 | - insn && &insn->list != &file->insn_list && \ | ||
8081 | - insn->sec == func->sec && \ | ||
8082 | - insn->offset < func->offset + func->len; \ | ||
8083 | - insn = list_next_entry(insn, list)) | ||
8084 | - | ||
8085 | -#define func_for_each_insn_continue_reverse(file, func, insn) \ | ||
8086 | - for (insn = list_prev_entry(insn, list); \ | ||
8087 | - &insn->list != &file->insn_list && \ | ||
8088 | - insn->sec == func->sec && insn->offset >= func->offset; \ | ||
8089 | - insn = list_prev_entry(insn, list)) | ||
8090 | - | ||
8091 | -#define sec_for_each_insn_from(file, insn) \ | ||
8092 | - for (; insn; insn = next_insn_same_sec(file, insn)) | ||
8093 | - | ||
8094 | - | ||
8095 | -/* | ||
8096 | - * Check if the function has been manually whitelisted with the | ||
8097 | - * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted | ||
8098 | - * due to its use of a context switching instruction. | ||
8099 | - */ | ||
8100 | -static bool ignore_func(struct objtool_file *file, struct symbol *func) | ||
8101 | -{ | ||
8102 | - struct rela *rela; | ||
8103 | - struct instruction *insn; | ||
8104 | - | ||
8105 | - /* check for STACK_FRAME_NON_STANDARD */ | ||
8106 | - if (file->whitelist && file->whitelist->rela) | ||
8107 | - list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) { | ||
8108 | - if (rela->sym->type == STT_SECTION && | ||
8109 | - rela->sym->sec == func->sec && | ||
8110 | - rela->addend == func->offset) | ||
8111 | - return true; | ||
8112 | - if (rela->sym->type == STT_FUNC && rela->sym == func) | ||
8113 | - return true; | ||
8114 | - } | ||
8115 | - | ||
8116 | - /* check if it has a context switching instruction */ | ||
8117 | - func_for_each_insn(file, func, insn) | ||
8118 | - if (insn->type == INSN_CONTEXT_SWITCH) | ||
8119 | - return true; | ||
8120 | - | ||
8121 | - return false; | ||
8122 | -} | ||
8123 | - | ||
8124 | -/* | ||
8125 | - * This checks to see if the given function is a "noreturn" function. | ||
8126 | - * | ||
8127 | - * For global functions which are outside the scope of this object file, we | ||
8128 | - * have to keep a manual list of them. | ||
8129 | - * | ||
8130 | - * For local functions, we have to detect them manually by simply looking for | ||
8131 | - * the lack of a return instruction. | ||
8132 | - * | ||
8133 | - * Returns: | ||
8134 | - * -1: error | ||
8135 | - * 0: no dead end | ||
8136 | - * 1: dead end | ||
8137 | - */ | ||
8138 | -static int __dead_end_function(struct objtool_file *file, struct symbol *func, | ||
8139 | - int recursion) | ||
8140 | -{ | ||
8141 | - int i; | ||
8142 | - struct instruction *insn; | ||
8143 | - bool empty = true; | ||
8144 | - | ||
8145 | - /* | ||
8146 | - * Unfortunately these have to be hard coded because the noreturn | ||
8147 | - * attribute isn't provided in ELF data. | ||
8148 | - */ | ||
8149 | - static const char * const global_noreturns[] = { | ||
8150 | - "__stack_chk_fail", | ||
8151 | - "panic", | ||
8152 | - "do_exit", | ||
8153 | - "do_task_dead", | ||
8154 | - "__module_put_and_exit", | ||
8155 | - "complete_and_exit", | ||
8156 | - "kvm_spurious_fault", | ||
8157 | - "__reiserfs_panic", | ||
8158 | - "lbug_with_loc" | ||
8159 | - }; | ||
8160 | - | ||
8161 | - if (func->bind == STB_WEAK) | ||
8162 | - return 0; | ||
8163 | - | ||
8164 | - if (func->bind == STB_GLOBAL) | ||
8165 | - for (i = 0; i < ARRAY_SIZE(global_noreturns); i++) | ||
8166 | - if (!strcmp(func->name, global_noreturns[i])) | ||
8167 | - return 1; | ||
8168 | - | ||
8169 | - if (!func->sec) | ||
8170 | - return 0; | ||
8171 | - | ||
8172 | - func_for_each_insn(file, func, insn) { | ||
8173 | - empty = false; | ||
8174 | - | ||
8175 | - if (insn->type == INSN_RETURN) | ||
8176 | - return 0; | ||
8177 | - } | ||
8178 | - | ||
8179 | - if (empty) | ||
8180 | - return 0; | ||
8181 | - | ||
8182 | - /* | ||
8183 | - * A function can have a sibling call instead of a return. In that | ||
8184 | - * case, the function's dead-end status depends on whether the target | ||
8185 | - * of the sibling call returns. | ||
8186 | - */ | ||
8187 | - func_for_each_insn(file, func, insn) { | ||
8188 | - if (insn->sec != func->sec || | ||
8189 | - insn->offset >= func->offset + func->len) | ||
8190 | - break; | ||
8191 | - | ||
8192 | - if (insn->type == INSN_JUMP_UNCONDITIONAL) { | ||
8193 | - struct instruction *dest = insn->jump_dest; | ||
8194 | - struct symbol *dest_func; | ||
8195 | - | ||
8196 | - if (!dest) | ||
8197 | - /* sibling call to another file */ | ||
8198 | - return 0; | ||
8199 | - | ||
8200 | - if (dest->sec != func->sec || | ||
8201 | - dest->offset < func->offset || | ||
8202 | - dest->offset >= func->offset + func->len) { | ||
8203 | - /* local sibling call */ | ||
8204 | - dest_func = find_symbol_by_offset(dest->sec, | ||
8205 | - dest->offset); | ||
8206 | - if (!dest_func) | ||
8207 | - continue; | ||
8208 | - | ||
8209 | - if (recursion == 5) { | ||
8210 | - WARN_FUNC("infinite recursion (objtool bug!)", | ||
8211 | - dest->sec, dest->offset); | ||
8212 | - return -1; | ||
8213 | - } | ||
8214 | - | ||
8215 | - return __dead_end_function(file, dest_func, | ||
8216 | - recursion + 1); | ||
8217 | - } | ||
8218 | - } | ||
8219 | - | ||
8220 | - if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts)) | ||
8221 | - /* sibling call */ | ||
8222 | - return 0; | ||
8223 | - } | ||
8224 | - | ||
8225 | - return 1; | ||
8226 | -} | ||
8227 | - | ||
8228 | -static int dead_end_function(struct objtool_file *file, struct symbol *func) | ||
8229 | -{ | ||
8230 | - return __dead_end_function(file, func, 0); | ||
8231 | -} | ||
8232 | - | ||
8233 | -/* | ||
8234 | - * Call the arch-specific instruction decoder for all the instructions and add | ||
8235 | - * them to the global instruction list. | ||
8236 | - */ | ||
8237 | -static int decode_instructions(struct objtool_file *file) | ||
8238 | -{ | ||
8239 | - struct section *sec; | ||
8240 | - struct symbol *func; | ||
8241 | - unsigned long offset; | ||
8242 | - struct instruction *insn; | ||
8243 | - int ret; | ||
8244 | - | ||
8245 | - list_for_each_entry(sec, &file->elf->sections, list) { | ||
8246 | - | ||
8247 | - if (!(sec->sh.sh_flags & SHF_EXECINSTR)) | ||
8248 | - continue; | ||
8249 | - | ||
8250 | - for (offset = 0; offset < sec->len; offset += insn->len) { | ||
8251 | - insn = malloc(sizeof(*insn)); | ||
8252 | - memset(insn, 0, sizeof(*insn)); | ||
8253 | - | ||
8254 | - INIT_LIST_HEAD(&insn->alts); | ||
8255 | - insn->sec = sec; | ||
8256 | - insn->offset = offset; | ||
8257 | - | ||
8258 | - ret = arch_decode_instruction(file->elf, sec, offset, | ||
8259 | - sec->len - offset, | ||
8260 | - &insn->len, &insn->type, | ||
8261 | - &insn->immediate); | ||
8262 | - if (ret) | ||
8263 | - return ret; | ||
8264 | - | ||
8265 | - if (!insn->type || insn->type > INSN_LAST) { | ||
8266 | - WARN_FUNC("invalid instruction type %d", | ||
8267 | - insn->sec, insn->offset, insn->type); | ||
8268 | - return -1; | ||
8269 | - } | ||
8270 | - | ||
8271 | - hash_add(file->insn_hash, &insn->hash, insn->offset); | ||
8272 | - list_add_tail(&insn->list, &file->insn_list); | ||
8273 | - } | ||
8274 | - | ||
8275 | - list_for_each_entry(func, &sec->symbol_list, list) { | ||
8276 | - if (func->type != STT_FUNC) | ||
8277 | - continue; | ||
8278 | - | ||
8279 | - if (!find_insn(file, sec, func->offset)) { | ||
8280 | - WARN("%s(): can't find starting instruction", | ||
8281 | - func->name); | ||
8282 | - return -1; | ||
8283 | - } | ||
8284 | - | ||
8285 | - func_for_each_insn(file, func, insn) | ||
8286 | - if (!insn->func) | ||
8287 | - insn->func = func; | ||
8288 | - } | ||
8289 | - } | ||
8290 | - | ||
8291 | - return 0; | ||
8292 | -} | ||
8293 | - | ||
8294 | -/* | ||
8295 | - * Warnings shouldn't be reported for ignored functions. | ||
8296 | - */ | ||
8297 | -static void add_ignores(struct objtool_file *file) | ||
8298 | -{ | ||
8299 | - struct instruction *insn; | ||
8300 | - struct section *sec; | ||
8301 | - struct symbol *func; | ||
8302 | - | ||
8303 | - list_for_each_entry(sec, &file->elf->sections, list) { | ||
8304 | - list_for_each_entry(func, &sec->symbol_list, list) { | ||
8305 | - if (func->type != STT_FUNC) | ||
8306 | - continue; | ||
8307 | - | ||
8308 | - if (!ignore_func(file, func)) | ||
8309 | - continue; | ||
8310 | - | ||
8311 | - func_for_each_insn(file, func, insn) | ||
8312 | - insn->visited = true; | ||
8313 | - } | ||
8314 | - } | ||
8315 | -} | ||
8316 | - | ||
8317 | -/* | ||
8318 | - * FIXME: For now, just ignore any alternatives which add retpolines. This is | ||
8319 | - * a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline. | ||
8320 | - * But it at least allows objtool to understand the control flow *around* the | ||
8321 | - * retpoline. | ||
8322 | - */ | ||
8323 | -static int add_nospec_ignores(struct objtool_file *file) | ||
8324 | -{ | ||
8325 | - struct section *sec; | ||
8326 | - struct rela *rela; | ||
8327 | - struct instruction *insn; | ||
8328 | - | ||
8329 | - sec = find_section_by_name(file->elf, ".rela.discard.nospec"); | ||
8330 | - if (!sec) | ||
8331 | - return 0; | ||
8332 | - | ||
8333 | - list_for_each_entry(rela, &sec->rela_list, list) { | ||
8334 | - if (rela->sym->type != STT_SECTION) { | ||
8335 | - WARN("unexpected relocation symbol type in %s", sec->name); | ||
8336 | - return -1; | ||
8337 | - } | ||
8338 | - | ||
8339 | - insn = find_insn(file, rela->sym->sec, rela->addend); | ||
8340 | - if (!insn) { | ||
8341 | - WARN("bad .discard.nospec entry"); | ||
8342 | - return -1; | ||
8343 | - } | ||
8344 | - | ||
8345 | - insn->ignore_alts = true; | ||
8346 | - } | ||
8347 | - | ||
8348 | - return 0; | ||
8349 | -} | ||
8350 | - | ||
8351 | -/* | ||
8352 | - * Find the destination instructions for all jumps. | ||
8353 | - */ | ||
8354 | -static int add_jump_destinations(struct objtool_file *file) | ||
8355 | -{ | ||
8356 | - struct instruction *insn; | ||
8357 | - struct rela *rela; | ||
8358 | - struct section *dest_sec; | ||
8359 | - unsigned long dest_off; | ||
8360 | - | ||
8361 | - for_each_insn(file, insn) { | ||
8362 | - if (insn->type != INSN_JUMP_CONDITIONAL && | ||
8363 | - insn->type != INSN_JUMP_UNCONDITIONAL) | ||
8364 | - continue; | ||
8365 | - | ||
8366 | - /* skip ignores */ | ||
8367 | - if (insn->visited) | ||
8368 | - continue; | ||
8369 | - | ||
8370 | - rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
8371 | - insn->len); | ||
8372 | - if (!rela) { | ||
8373 | - dest_sec = insn->sec; | ||
8374 | - dest_off = insn->offset + insn->len + insn->immediate; | ||
8375 | - } else if (rela->sym->type == STT_SECTION) { | ||
8376 | - dest_sec = rela->sym->sec; | ||
8377 | - dest_off = rela->addend + 4; | ||
8378 | - } else if (rela->sym->sec->idx) { | ||
8379 | - dest_sec = rela->sym->sec; | ||
8380 | - dest_off = rela->sym->sym.st_value + rela->addend + 4; | ||
8381 | - } else if (strstr(rela->sym->name, "_indirect_thunk_")) { | ||
8382 | - /* | ||
8383 | - * Retpoline jumps are really dynamic jumps in | ||
8384 | - * disguise, so convert them accordingly. | ||
8385 | - */ | ||
8386 | - insn->type = INSN_JUMP_DYNAMIC; | ||
8387 | - continue; | ||
8388 | - } else { | ||
8389 | - /* sibling call */ | ||
8390 | - insn->jump_dest = 0; | ||
8391 | - continue; | ||
8392 | - } | ||
8393 | - | ||
8394 | - insn->jump_dest = find_insn(file, dest_sec, dest_off); | ||
8395 | - if (!insn->jump_dest) { | ||
8396 | - | ||
8397 | - /* | ||
8398 | - * This is a special case where an alt instruction | ||
8399 | - * jumps past the end of the section. These are | ||
8400 | - * handled later in handle_group_alt(). | ||
8401 | - */ | ||
8402 | - if (!strcmp(insn->sec->name, ".altinstr_replacement")) | ||
8403 | - continue; | ||
8404 | - | ||
8405 | - WARN_FUNC("can't find jump dest instruction at %s+0x%lx", | ||
8406 | - insn->sec, insn->offset, dest_sec->name, | ||
8407 | - dest_off); | ||
8408 | - return -1; | ||
8409 | - } | ||
8410 | - } | ||
8411 | - | ||
8412 | - return 0; | ||
8413 | -} | ||
8414 | - | ||
8415 | -/* | ||
8416 | - * Find the destination instructions for all calls. | ||
8417 | - */ | ||
8418 | -static int add_call_destinations(struct objtool_file *file) | ||
8419 | -{ | ||
8420 | - struct instruction *insn; | ||
8421 | - unsigned long dest_off; | ||
8422 | - struct rela *rela; | ||
8423 | - | ||
8424 | - for_each_insn(file, insn) { | ||
8425 | - if (insn->type != INSN_CALL) | ||
8426 | - continue; | ||
8427 | - | ||
8428 | - rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
8429 | - insn->len); | ||
8430 | - if (!rela) { | ||
8431 | - dest_off = insn->offset + insn->len + insn->immediate; | ||
8432 | - insn->call_dest = find_symbol_by_offset(insn->sec, | ||
8433 | - dest_off); | ||
8434 | - /* | ||
8435 | - * FIXME: Thanks to retpolines, it's now considered | ||
8436 | - * normal for a function to call within itself. So | ||
8437 | - * disable this warning for now. | ||
8438 | - */ | ||
8439 | -#if 0 | ||
8440 | - if (!insn->call_dest) { | ||
8441 | - WARN_FUNC("can't find call dest symbol at offset 0x%lx", | ||
8442 | - insn->sec, insn->offset, dest_off); | ||
8443 | - return -1; | ||
8444 | - } | ||
8445 | -#endif | ||
8446 | - } else if (rela->sym->type == STT_SECTION) { | ||
8447 | - insn->call_dest = find_symbol_by_offset(rela->sym->sec, | ||
8448 | - rela->addend+4); | ||
8449 | - if (!insn->call_dest || | ||
8450 | - insn->call_dest->type != STT_FUNC) { | ||
8451 | - WARN_FUNC("can't find call dest symbol at %s+0x%x", | ||
8452 | - insn->sec, insn->offset, | ||
8453 | - rela->sym->sec->name, | ||
8454 | - rela->addend + 4); | ||
8455 | - return -1; | ||
8456 | - } | ||
8457 | - } else | ||
8458 | - insn->call_dest = rela->sym; | ||
8459 | - } | ||
8460 | - | ||
8461 | - return 0; | ||
8462 | -} | ||
8463 | - | ||
8464 | -/* | ||
8465 | - * The .alternatives section requires some extra special care, over and above | ||
8466 | - * what other special sections require: | ||
8467 | - * | ||
8468 | - * 1. Because alternatives are patched in-place, we need to insert a fake jump | ||
8469 | - * instruction at the end so that validate_branch() skips all the original | ||
8470 | - * replaced instructions when validating the new instruction path. | ||
8471 | - * | ||
8472 | - * 2. An added wrinkle is that the new instruction length might be zero. In | ||
8473 | - * that case the old instructions are replaced with noops. We simulate that | ||
8474 | - * by creating a fake jump as the only new instruction. | ||
8475 | - * | ||
8476 | - * 3. In some cases, the alternative section includes an instruction which | ||
8477 | - * conditionally jumps to the _end_ of the entry. We have to modify these | ||
8478 | - * jumps' destinations to point back to .text rather than the end of the | ||
8479 | - * entry in .altinstr_replacement. | ||
8480 | - * | ||
8481 | - * 4. It has been requested that we don't validate the !POPCNT feature path | ||
8482 | - * which is a "very very small percentage of machines". | ||
8483 | - */ | ||
8484 | -static int handle_group_alt(struct objtool_file *file, | ||
8485 | - struct special_alt *special_alt, | ||
8486 | - struct instruction *orig_insn, | ||
8487 | - struct instruction **new_insn) | ||
8488 | -{ | ||
8489 | - struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; | ||
8490 | - unsigned long dest_off; | ||
8491 | - | ||
8492 | - last_orig_insn = NULL; | ||
8493 | - insn = orig_insn; | ||
8494 | - sec_for_each_insn_from(file, insn) { | ||
8495 | - if (insn->offset >= special_alt->orig_off + special_alt->orig_len) | ||
8496 | - break; | ||
8497 | - | ||
8498 | - if (special_alt->skip_orig) | ||
8499 | - insn->type = INSN_NOP; | ||
8500 | - | ||
8501 | - insn->alt_group = true; | ||
8502 | - last_orig_insn = insn; | ||
8503 | - } | ||
8504 | - | ||
8505 | - if (!next_insn_same_sec(file, last_orig_insn)) { | ||
8506 | - WARN("%s: don't know how to handle alternatives at end of section", | ||
8507 | - special_alt->orig_sec->name); | ||
8508 | - return -1; | ||
8509 | - } | ||
8510 | - | ||
8511 | - fake_jump = malloc(sizeof(*fake_jump)); | ||
8512 | - if (!fake_jump) { | ||
8513 | - WARN("malloc failed"); | ||
8514 | - return -1; | ||
8515 | - } | ||
8516 | - memset(fake_jump, 0, sizeof(*fake_jump)); | ||
8517 | - INIT_LIST_HEAD(&fake_jump->alts); | ||
8518 | - fake_jump->sec = special_alt->new_sec; | ||
8519 | - fake_jump->offset = -1; | ||
8520 | - fake_jump->type = INSN_JUMP_UNCONDITIONAL; | ||
8521 | - fake_jump->jump_dest = list_next_entry(last_orig_insn, list); | ||
8522 | - | ||
8523 | - if (!special_alt->new_len) { | ||
8524 | - *new_insn = fake_jump; | ||
8525 | - return 0; | ||
8526 | - } | ||
8527 | - | ||
8528 | - last_new_insn = NULL; | ||
8529 | - insn = *new_insn; | ||
8530 | - sec_for_each_insn_from(file, insn) { | ||
8531 | - if (insn->offset >= special_alt->new_off + special_alt->new_len) | ||
8532 | - break; | ||
8533 | - | ||
8534 | - last_new_insn = insn; | ||
8535 | - | ||
8536 | - if (insn->type != INSN_JUMP_CONDITIONAL && | ||
8537 | - insn->type != INSN_JUMP_UNCONDITIONAL) | ||
8538 | - continue; | ||
8539 | - | ||
8540 | - if (!insn->immediate) | ||
8541 | - continue; | ||
8542 | - | ||
8543 | - dest_off = insn->offset + insn->len + insn->immediate; | ||
8544 | - if (dest_off == special_alt->new_off + special_alt->new_len) | ||
8545 | - insn->jump_dest = fake_jump; | ||
8546 | - | ||
8547 | - if (!insn->jump_dest) { | ||
8548 | - WARN_FUNC("can't find alternative jump destination", | ||
8549 | - insn->sec, insn->offset); | ||
8550 | - return -1; | ||
8551 | - } | ||
8552 | - } | ||
8553 | - | ||
8554 | - if (!last_new_insn) { | ||
8555 | - WARN_FUNC("can't find last new alternative instruction", | ||
8556 | - special_alt->new_sec, special_alt->new_off); | ||
8557 | - return -1; | ||
8558 | - } | ||
8559 | - | ||
8560 | - list_add(&fake_jump->list, &last_new_insn->list); | ||
8561 | - | ||
8562 | - return 0; | ||
8563 | -} | ||
8564 | - | ||
8565 | -/* | ||
8566 | - * A jump table entry can either convert a nop to a jump or a jump to a nop. | ||
8567 | - * If the original instruction is a jump, make the alt entry an effective nop | ||
8568 | - * by just skipping the original instruction. | ||
8569 | - */ | ||
8570 | -static int handle_jump_alt(struct objtool_file *file, | ||
8571 | - struct special_alt *special_alt, | ||
8572 | - struct instruction *orig_insn, | ||
8573 | - struct instruction **new_insn) | ||
8574 | -{ | ||
8575 | - if (orig_insn->type == INSN_NOP) | ||
8576 | - return 0; | ||
8577 | - | ||
8578 | - if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) { | ||
8579 | - WARN_FUNC("unsupported instruction at jump label", | ||
8580 | - orig_insn->sec, orig_insn->offset); | ||
8581 | - return -1; | ||
8582 | - } | ||
8583 | - | ||
8584 | - *new_insn = list_next_entry(orig_insn, list); | ||
8585 | - return 0; | ||
8586 | -} | ||
8587 | - | ||
8588 | -/* | ||
8589 | - * Read all the special sections which have alternate instructions which can be | ||
8590 | - * patched in or redirected to at runtime. Each instruction having alternate | ||
8591 | - * instruction(s) has them added to its insn->alts list, which will be | ||
8592 | - * traversed in validate_branch(). | ||
8593 | - */ | ||
8594 | -static int add_special_section_alts(struct objtool_file *file) | ||
8595 | -{ | ||
8596 | - struct list_head special_alts; | ||
8597 | - struct instruction *orig_insn, *new_insn; | ||
8598 | - struct special_alt *special_alt, *tmp; | ||
8599 | - struct alternative *alt; | ||
8600 | - int ret; | ||
8601 | - | ||
8602 | - ret = special_get_alts(file->elf, &special_alts); | ||
8603 | - if (ret) | ||
8604 | - return ret; | ||
8605 | - | ||
8606 | - list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { | ||
8607 | - | ||
8608 | - orig_insn = find_insn(file, special_alt->orig_sec, | ||
8609 | - special_alt->orig_off); | ||
8610 | - if (!orig_insn) { | ||
8611 | - WARN_FUNC("special: can't find orig instruction", | ||
8612 | - special_alt->orig_sec, special_alt->orig_off); | ||
8613 | - ret = -1; | ||
8614 | - goto out; | ||
8615 | - } | ||
8616 | - | ||
8617 | - /* Ignore retpoline alternatives. */ | ||
8618 | - if (orig_insn->ignore_alts) | ||
8619 | - continue; | ||
8620 | - | ||
8621 | - new_insn = NULL; | ||
8622 | - if (!special_alt->group || special_alt->new_len) { | ||
8623 | - new_insn = find_insn(file, special_alt->new_sec, | ||
8624 | - special_alt->new_off); | ||
8625 | - if (!new_insn) { | ||
8626 | - WARN_FUNC("special: can't find new instruction", | ||
8627 | - special_alt->new_sec, | ||
8628 | - special_alt->new_off); | ||
8629 | - ret = -1; | ||
8630 | - goto out; | ||
8631 | - } | ||
8632 | - } | ||
8633 | +#include "check.h" | ||
8634 | |||
8635 | - if (special_alt->group) { | ||
8636 | - ret = handle_group_alt(file, special_alt, orig_insn, | ||
8637 | - &new_insn); | ||
8638 | - if (ret) | ||
8639 | - goto out; | ||
8640 | - } else if (special_alt->jump_or_nop) { | ||
8641 | - ret = handle_jump_alt(file, special_alt, orig_insn, | ||
8642 | - &new_insn); | ||
8643 | - if (ret) | ||
8644 | - goto out; | ||
8645 | - } | ||
8646 | +bool no_fp, no_unreachable, retpoline, module; | ||
8647 | |||
8648 | - alt = malloc(sizeof(*alt)); | ||
8649 | - if (!alt) { | ||
8650 | - WARN("malloc failed"); | ||
8651 | - ret = -1; | ||
8652 | - goto out; | ||
8653 | - } | ||
8654 | - | ||
8655 | - alt->insn = new_insn; | ||
8656 | - list_add_tail(&alt->list, &orig_insn->alts); | ||
8657 | - | ||
8658 | - list_del(&special_alt->list); | ||
8659 | - free(special_alt); | ||
8660 | - } | ||
8661 | - | ||
8662 | -out: | ||
8663 | - return ret; | ||
8664 | -} | ||
8665 | - | ||
8666 | -static int add_switch_table(struct objtool_file *file, struct symbol *func, | ||
8667 | - struct instruction *insn, struct rela *table, | ||
8668 | - struct rela *next_table) | ||
8669 | -{ | ||
8670 | - struct rela *rela = table; | ||
8671 | - struct instruction *alt_insn; | ||
8672 | - struct alternative *alt; | ||
8673 | - | ||
8674 | - list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { | ||
8675 | - if (rela == next_table) | ||
8676 | - break; | ||
8677 | - | ||
8678 | - if (rela->sym->sec != insn->sec || | ||
8679 | - rela->addend <= func->offset || | ||
8680 | - rela->addend >= func->offset + func->len) | ||
8681 | - break; | ||
8682 | - | ||
8683 | - alt_insn = find_insn(file, insn->sec, rela->addend); | ||
8684 | - if (!alt_insn) { | ||
8685 | - WARN("%s: can't find instruction at %s+0x%x", | ||
8686 | - file->rodata->rela->name, insn->sec->name, | ||
8687 | - rela->addend); | ||
8688 | - return -1; | ||
8689 | - } | ||
8690 | - | ||
8691 | - alt = malloc(sizeof(*alt)); | ||
8692 | - if (!alt) { | ||
8693 | - WARN("malloc failed"); | ||
8694 | - return -1; | ||
8695 | - } | ||
8696 | - | ||
8697 | - alt->insn = alt_insn; | ||
8698 | - list_add_tail(&alt->list, &insn->alts); | ||
8699 | - } | ||
8700 | - | ||
8701 | - return 0; | ||
8702 | -} | ||
8703 | - | ||
8704 | -/* | ||
8705 | - * find_switch_table() - Given a dynamic jump, find the switch jump table in | ||
8706 | - * .rodata associated with it. | ||
8707 | - * | ||
8708 | - * There are 3 basic patterns: | ||
8709 | - * | ||
8710 | - * 1. jmpq *[rodata addr](,%reg,8) | ||
8711 | - * | ||
8712 | - * This is the most common case by far. It jumps to an address in a simple | ||
8713 | - * jump table which is stored in .rodata. | ||
8714 | - * | ||
8715 | - * 2. jmpq *[rodata addr](%rip) | ||
8716 | - * | ||
8717 | - * This is caused by a rare GCC quirk, currently only seen in three driver | ||
8718 | - * functions in the kernel, only with certain obscure non-distro configs. | ||
8719 | - * | ||
8720 | - * As part of an optimization, GCC makes a copy of an existing switch jump | ||
8721 | - * table, modifies it, and then hard-codes the jump (albeit with an indirect | ||
8722 | - * jump) to use a single entry in the table. The rest of the jump table and | ||
8723 | - * some of its jump targets remain as dead code. | ||
8724 | - * | ||
8725 | - * In such a case we can just crudely ignore all unreachable instruction | ||
8726 | - * warnings for the entire object file. Ideally we would just ignore them | ||
8727 | - * for the function, but that would require redesigning the code quite a | ||
8728 | - * bit. And honestly that's just not worth doing: unreachable instruction | ||
8729 | - * warnings are of questionable value anyway, and this is such a rare issue. | ||
8730 | - * | ||
8731 | - * 3. mov [rodata addr],%reg1 | ||
8732 | - * ... some instructions ... | ||
8733 | - * jmpq *(%reg1,%reg2,8) | ||
8734 | - * | ||
8735 | - * This is a fairly uncommon pattern which is new for GCC 6. As of this | ||
8736 | - * writing, there are 11 occurrences of it in the allmodconfig kernel. | ||
8737 | - * | ||
8738 | - * TODO: Once we have DWARF CFI and smarter instruction decoding logic, | ||
8739 | - * ensure the same register is used in the mov and jump instructions. | ||
8740 | - */ | ||
8741 | -static struct rela *find_switch_table(struct objtool_file *file, | ||
8742 | - struct symbol *func, | ||
8743 | - struct instruction *insn) | ||
8744 | -{ | ||
8745 | - struct rela *text_rela, *rodata_rela; | ||
8746 | - struct instruction *orig_insn = insn; | ||
8747 | - | ||
8748 | - text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); | ||
8749 | - if (text_rela && text_rela->sym == file->rodata->sym) { | ||
8750 | - /* case 1 */ | ||
8751 | - rodata_rela = find_rela_by_dest(file->rodata, | ||
8752 | - text_rela->addend); | ||
8753 | - if (rodata_rela) | ||
8754 | - return rodata_rela; | ||
8755 | - | ||
8756 | - /* case 2 */ | ||
8757 | - rodata_rela = find_rela_by_dest(file->rodata, | ||
8758 | - text_rela->addend + 4); | ||
8759 | - if (!rodata_rela) | ||
8760 | - return NULL; | ||
8761 | - file->ignore_unreachables = true; | ||
8762 | - return rodata_rela; | ||
8763 | - } | ||
8764 | - | ||
8765 | - /* case 3 */ | ||
8766 | - func_for_each_insn_continue_reverse(file, func, insn) { | ||
8767 | - if (insn->type == INSN_JUMP_DYNAMIC) | ||
8768 | - break; | ||
8769 | - | ||
8770 | - /* allow small jumps within the range */ | ||
8771 | - if (insn->type == INSN_JUMP_UNCONDITIONAL && | ||
8772 | - insn->jump_dest && | ||
8773 | - (insn->jump_dest->offset <= insn->offset || | ||
8774 | - insn->jump_dest->offset > orig_insn->offset)) | ||
8775 | - break; | ||
8776 | - | ||
8777 | - /* look for a relocation which references .rodata */ | ||
8778 | - text_rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
8779 | - insn->len); | ||
8780 | - if (!text_rela || text_rela->sym != file->rodata->sym) | ||
8781 | - continue; | ||
8782 | - | ||
8783 | - /* | ||
8784 | - * Make sure the .rodata address isn't associated with a | ||
8785 | - * symbol. gcc jump tables are anonymous data. | ||
8786 | - */ | ||
8787 | - if (find_symbol_containing(file->rodata, text_rela->addend)) | ||
8788 | - continue; | ||
8789 | - | ||
8790 | - return find_rela_by_dest(file->rodata, text_rela->addend); | ||
8791 | - } | ||
8792 | - | ||
8793 | - return NULL; | ||
8794 | -} | ||
8795 | - | ||
8796 | -static int add_func_switch_tables(struct objtool_file *file, | ||
8797 | - struct symbol *func) | ||
8798 | -{ | ||
8799 | - struct instruction *insn, *prev_jump = NULL; | ||
8800 | - struct rela *rela, *prev_rela = NULL; | ||
8801 | - int ret; | ||
8802 | - | ||
8803 | - func_for_each_insn(file, func, insn) { | ||
8804 | - if (insn->type != INSN_JUMP_DYNAMIC) | ||
8805 | - continue; | ||
8806 | - | ||
8807 | - rela = find_switch_table(file, func, insn); | ||
8808 | - if (!rela) | ||
8809 | - continue; | ||
8810 | - | ||
8811 | - /* | ||
8812 | - * We found a switch table, but we don't know yet how big it | ||
8813 | - * is. Don't add it until we reach the end of the function or | ||
8814 | - * the beginning of another switch table in the same function. | ||
8815 | - */ | ||
8816 | - if (prev_jump) { | ||
8817 | - ret = add_switch_table(file, func, prev_jump, prev_rela, | ||
8818 | - rela); | ||
8819 | - if (ret) | ||
8820 | - return ret; | ||
8821 | - } | ||
8822 | - | ||
8823 | - prev_jump = insn; | ||
8824 | - prev_rela = rela; | ||
8825 | - } | ||
8826 | - | ||
8827 | - if (prev_jump) { | ||
8828 | - ret = add_switch_table(file, func, prev_jump, prev_rela, NULL); | ||
8829 | - if (ret) | ||
8830 | - return ret; | ||
8831 | - } | ||
8832 | - | ||
8833 | - return 0; | ||
8834 | -} | ||
8835 | - | ||
8836 | -/* | ||
8837 | - * For some switch statements, gcc generates a jump table in the .rodata | ||
8838 | - * section which contains a list of addresses within the function to jump to. | ||
8839 | - * This finds these jump tables and adds them to the insn->alts lists. | ||
8840 | - */ | ||
8841 | -static int add_switch_table_alts(struct objtool_file *file) | ||
8842 | -{ | ||
8843 | - struct section *sec; | ||
8844 | - struct symbol *func; | ||
8845 | - int ret; | ||
8846 | - | ||
8847 | - if (!file->rodata || !file->rodata->rela) | ||
8848 | - return 0; | ||
8849 | - | ||
8850 | - list_for_each_entry(sec, &file->elf->sections, list) { | ||
8851 | - list_for_each_entry(func, &sec->symbol_list, list) { | ||
8852 | - if (func->type != STT_FUNC) | ||
8853 | - continue; | ||
8854 | - | ||
8855 | - ret = add_func_switch_tables(file, func); | ||
8856 | - if (ret) | ||
8857 | - return ret; | ||
8858 | - } | ||
8859 | - } | ||
8860 | - | ||
8861 | - return 0; | ||
8862 | -} | ||
8863 | - | ||
8864 | -static int decode_sections(struct objtool_file *file) | ||
8865 | -{ | ||
8866 | - int ret; | ||
8867 | - | ||
8868 | - ret = decode_instructions(file); | ||
8869 | - if (ret) | ||
8870 | - return ret; | ||
8871 | - | ||
8872 | - add_ignores(file); | ||
8873 | - | ||
8874 | - ret = add_nospec_ignores(file); | ||
8875 | - if (ret) | ||
8876 | - return ret; | ||
8877 | - | ||
8878 | - ret = add_jump_destinations(file); | ||
8879 | - if (ret) | ||
8880 | - return ret; | ||
8881 | - | ||
8882 | - ret = add_call_destinations(file); | ||
8883 | - if (ret) | ||
8884 | - return ret; | ||
8885 | - | ||
8886 | - ret = add_special_section_alts(file); | ||
8887 | - if (ret) | ||
8888 | - return ret; | ||
8889 | - | ||
8890 | - ret = add_switch_table_alts(file); | ||
8891 | - if (ret) | ||
8892 | - return ret; | ||
8893 | - | ||
8894 | - return 0; | ||
8895 | -} | ||
8896 | - | ||
8897 | -static bool is_fentry_call(struct instruction *insn) | ||
8898 | -{ | ||
8899 | - if (insn->type == INSN_CALL && | ||
8900 | - insn->call_dest->type == STT_NOTYPE && | ||
8901 | - !strcmp(insn->call_dest->name, "__fentry__")) | ||
8902 | - return true; | ||
8903 | - | ||
8904 | - return false; | ||
8905 | -} | ||
8906 | - | ||
8907 | -static bool has_modified_stack_frame(struct instruction *insn) | ||
8908 | -{ | ||
8909 | - return (insn->state & STATE_FP_SAVED) || | ||
8910 | - (insn->state & STATE_FP_SETUP); | ||
8911 | -} | ||
8912 | - | ||
8913 | -static bool has_valid_stack_frame(struct instruction *insn) | ||
8914 | -{ | ||
8915 | - return (insn->state & STATE_FP_SAVED) && | ||
8916 | - (insn->state & STATE_FP_SETUP); | ||
8917 | -} | ||
8918 | - | ||
8919 | -static unsigned int frame_state(unsigned long state) | ||
8920 | -{ | ||
8921 | - return (state & (STATE_FP_SAVED | STATE_FP_SETUP)); | ||
8922 | -} | ||
8923 | - | ||
8924 | -/* | ||
8925 | - * Follow the branch starting at the given instruction, and recursively follow | ||
8926 | - * any other branches (jumps). Meanwhile, track the frame pointer state at | ||
8927 | - * each instruction and validate all the rules described in | ||
8928 | - * tools/objtool/Documentation/stack-validation.txt. | ||
8929 | - */ | ||
8930 | -static int validate_branch(struct objtool_file *file, | ||
8931 | - struct instruction *first, unsigned char first_state) | ||
8932 | -{ | ||
8933 | - struct alternative *alt; | ||
8934 | - struct instruction *insn; | ||
8935 | - struct section *sec; | ||
8936 | - struct symbol *func = NULL; | ||
8937 | - unsigned char state; | ||
8938 | - int ret; | ||
8939 | - | ||
8940 | - insn = first; | ||
8941 | - sec = insn->sec; | ||
8942 | - state = first_state; | ||
8943 | - | ||
8944 | - if (insn->alt_group && list_empty(&insn->alts)) { | ||
8945 | - WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", | ||
8946 | - sec, insn->offset); | ||
8947 | - return 1; | ||
8948 | - } | ||
8949 | - | ||
8950 | - while (1) { | ||
8951 | - if (file->c_file && insn->func) { | ||
8952 | - if (func && func != insn->func) { | ||
8953 | - WARN("%s() falls through to next function %s()", | ||
8954 | - func->name, insn->func->name); | ||
8955 | - return 1; | ||
8956 | - } | ||
8957 | - | ||
8958 | - func = insn->func; | ||
8959 | - } | ||
8960 | - | ||
8961 | - if (insn->visited) { | ||
8962 | - if (frame_state(insn->state) != frame_state(state)) { | ||
8963 | - WARN_FUNC("frame pointer state mismatch", | ||
8964 | - sec, insn->offset); | ||
8965 | - return 1; | ||
8966 | - } | ||
8967 | - | ||
8968 | - return 0; | ||
8969 | - } | ||
8970 | - | ||
8971 | - insn->visited = true; | ||
8972 | - insn->state = state; | ||
8973 | - | ||
8974 | - list_for_each_entry(alt, &insn->alts, list) { | ||
8975 | - ret = validate_branch(file, alt->insn, state); | ||
8976 | - if (ret) | ||
8977 | - return 1; | ||
8978 | - } | ||
8979 | - | ||
8980 | - switch (insn->type) { | ||
8981 | - | ||
8982 | - case INSN_FP_SAVE: | ||
8983 | - if (!nofp) { | ||
8984 | - if (state & STATE_FP_SAVED) { | ||
8985 | - WARN_FUNC("duplicate frame pointer save", | ||
8986 | - sec, insn->offset); | ||
8987 | - return 1; | ||
8988 | - } | ||
8989 | - state |= STATE_FP_SAVED; | ||
8990 | - } | ||
8991 | - break; | ||
8992 | - | ||
8993 | - case INSN_FP_SETUP: | ||
8994 | - if (!nofp) { | ||
8995 | - if (state & STATE_FP_SETUP) { | ||
8996 | - WARN_FUNC("duplicate frame pointer setup", | ||
8997 | - sec, insn->offset); | ||
8998 | - return 1; | ||
8999 | - } | ||
9000 | - state |= STATE_FP_SETUP; | ||
9001 | - } | ||
9002 | - break; | ||
9003 | - | ||
9004 | - case INSN_FP_RESTORE: | ||
9005 | - if (!nofp) { | ||
9006 | - if (has_valid_stack_frame(insn)) | ||
9007 | - state &= ~STATE_FP_SETUP; | ||
9008 | - | ||
9009 | - state &= ~STATE_FP_SAVED; | ||
9010 | - } | ||
9011 | - break; | ||
9012 | - | ||
9013 | - case INSN_RETURN: | ||
9014 | - if (!nofp && has_modified_stack_frame(insn)) { | ||
9015 | - WARN_FUNC("return without frame pointer restore", | ||
9016 | - sec, insn->offset); | ||
9017 | - return 1; | ||
9018 | - } | ||
9019 | - return 0; | ||
9020 | - | ||
9021 | - case INSN_CALL: | ||
9022 | - if (is_fentry_call(insn)) { | ||
9023 | - state |= STATE_FENTRY; | ||
9024 | - break; | ||
9025 | - } | ||
9026 | - | ||
9027 | - ret = dead_end_function(file, insn->call_dest); | ||
9028 | - if (ret == 1) | ||
9029 | - return 0; | ||
9030 | - if (ret == -1) | ||
9031 | - return 1; | ||
9032 | - | ||
9033 | - /* fallthrough */ | ||
9034 | - case INSN_CALL_DYNAMIC: | ||
9035 | - if (!nofp && !has_valid_stack_frame(insn)) { | ||
9036 | - WARN_FUNC("call without frame pointer save/setup", | ||
9037 | - sec, insn->offset); | ||
9038 | - return 1; | ||
9039 | - } | ||
9040 | - break; | ||
9041 | - | ||
9042 | - case INSN_JUMP_CONDITIONAL: | ||
9043 | - case INSN_JUMP_UNCONDITIONAL: | ||
9044 | - if (insn->jump_dest) { | ||
9045 | - ret = validate_branch(file, insn->jump_dest, | ||
9046 | - state); | ||
9047 | - if (ret) | ||
9048 | - return 1; | ||
9049 | - } else if (has_modified_stack_frame(insn)) { | ||
9050 | - WARN_FUNC("sibling call from callable instruction with changed frame pointer", | ||
9051 | - sec, insn->offset); | ||
9052 | - return 1; | ||
9053 | - } /* else it's a sibling call */ | ||
9054 | - | ||
9055 | - if (insn->type == INSN_JUMP_UNCONDITIONAL) | ||
9056 | - return 0; | ||
9057 | - | ||
9058 | - break; | ||
9059 | - | ||
9060 | - case INSN_JUMP_DYNAMIC: | ||
9061 | - if (list_empty(&insn->alts) && | ||
9062 | - has_modified_stack_frame(insn)) { | ||
9063 | - WARN_FUNC("sibling call from callable instruction with changed frame pointer", | ||
9064 | - sec, insn->offset); | ||
9065 | - return 1; | ||
9066 | - } | ||
9067 | - | ||
9068 | - return 0; | ||
9069 | - | ||
9070 | - case INSN_BUG: | ||
9071 | - return 0; | ||
9072 | - | ||
9073 | - default: | ||
9074 | - break; | ||
9075 | - } | ||
9076 | - | ||
9077 | - insn = next_insn_same_sec(file, insn); | ||
9078 | - if (!insn) { | ||
9079 | - WARN("%s: unexpected end of section", sec->name); | ||
9080 | - return 1; | ||
9081 | - } | ||
9082 | - } | ||
9083 | - | ||
9084 | - return 0; | ||
9085 | -} | ||
9086 | - | ||
9087 | -static bool is_kasan_insn(struct instruction *insn) | ||
9088 | -{ | ||
9089 | - return (insn->type == INSN_CALL && | ||
9090 | - !strcmp(insn->call_dest->name, "__asan_handle_no_return")); | ||
9091 | -} | ||
9092 | - | ||
9093 | -static bool is_ubsan_insn(struct instruction *insn) | ||
9094 | -{ | ||
9095 | - return (insn->type == INSN_CALL && | ||
9096 | - !strcmp(insn->call_dest->name, | ||
9097 | - "__ubsan_handle_builtin_unreachable")); | ||
9098 | -} | ||
9099 | - | ||
9100 | -static bool ignore_unreachable_insn(struct symbol *func, | ||
9101 | - struct instruction *insn) | ||
9102 | -{ | ||
9103 | - int i; | ||
9104 | - | ||
9105 | - if (insn->type == INSN_NOP) | ||
9106 | - return true; | ||
9107 | - | ||
9108 | - /* | ||
9109 | - * Check if this (or a subsequent) instruction is related to | ||
9110 | - * CONFIG_UBSAN or CONFIG_KASAN. | ||
9111 | - * | ||
9112 | - * End the search at 5 instructions to avoid going into the weeds. | ||
9113 | - */ | ||
9114 | - for (i = 0; i < 5; i++) { | ||
9115 | - | ||
9116 | - if (is_kasan_insn(insn) || is_ubsan_insn(insn)) | ||
9117 | - return true; | ||
9118 | - | ||
9119 | - if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { | ||
9120 | - insn = insn->jump_dest; | ||
9121 | - continue; | ||
9122 | - } | ||
9123 | - | ||
9124 | - if (insn->offset + insn->len >= func->offset + func->len) | ||
9125 | - break; | ||
9126 | - insn = list_next_entry(insn, list); | ||
9127 | - } | ||
9128 | - | ||
9129 | - return false; | ||
9130 | -} | ||
9131 | - | ||
9132 | -static int validate_functions(struct objtool_file *file) | ||
9133 | -{ | ||
9134 | - struct section *sec; | ||
9135 | - struct symbol *func; | ||
9136 | - struct instruction *insn; | ||
9137 | - int ret, warnings = 0; | ||
9138 | - | ||
9139 | - list_for_each_entry(sec, &file->elf->sections, list) { | ||
9140 | - list_for_each_entry(func, &sec->symbol_list, list) { | ||
9141 | - if (func->type != STT_FUNC) | ||
9142 | - continue; | ||
9143 | - | ||
9144 | - insn = find_insn(file, sec, func->offset); | ||
9145 | - if (!insn) | ||
9146 | - continue; | ||
9147 | - | ||
9148 | - ret = validate_branch(file, insn, 0); | ||
9149 | - warnings += ret; | ||
9150 | - } | ||
9151 | - } | ||
9152 | - | ||
9153 | - list_for_each_entry(sec, &file->elf->sections, list) { | ||
9154 | - list_for_each_entry(func, &sec->symbol_list, list) { | ||
9155 | - if (func->type != STT_FUNC) | ||
9156 | - continue; | ||
9157 | - | ||
9158 | - func_for_each_insn(file, func, insn) { | ||
9159 | - if (insn->visited) | ||
9160 | - continue; | ||
9161 | - | ||
9162 | - insn->visited = true; | ||
9163 | - | ||
9164 | - if (file->ignore_unreachables || warnings || | ||
9165 | - ignore_unreachable_insn(func, insn)) | ||
9166 | - continue; | ||
9167 | - | ||
9168 | - /* | ||
9169 | - * gcov produces a lot of unreachable | ||
9170 | - * instructions. If we get an unreachable | ||
9171 | - * warning and the file has gcov enabled, just | ||
9172 | - * ignore it, and all other such warnings for | ||
9173 | - * the file. | ||
9174 | - */ | ||
9175 | - if (!file->ignore_unreachables && | ||
9176 | - gcov_enabled(file)) { | ||
9177 | - file->ignore_unreachables = true; | ||
9178 | - continue; | ||
9179 | - } | ||
9180 | - | ||
9181 | - WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); | ||
9182 | - warnings++; | ||
9183 | - } | ||
9184 | - } | ||
9185 | - } | ||
9186 | - | ||
9187 | - return warnings; | ||
9188 | -} | ||
9189 | - | ||
9190 | -static int validate_uncallable_instructions(struct objtool_file *file) | ||
9191 | -{ | ||
9192 | - struct instruction *insn; | ||
9193 | - int warnings = 0; | ||
9194 | - | ||
9195 | - for_each_insn(file, insn) { | ||
9196 | - if (!insn->visited && insn->type == INSN_RETURN) { | ||
9197 | - | ||
9198 | - /* | ||
9199 | - * Don't warn about call instructions in unvisited | ||
9200 | - * retpoline alternatives. | ||
9201 | - */ | ||
9202 | - if (!strcmp(insn->sec->name, ".altinstr_replacement")) | ||
9203 | - continue; | ||
9204 | - | ||
9205 | - WARN_FUNC("return instruction outside of a callable function", | ||
9206 | - insn->sec, insn->offset); | ||
9207 | - warnings++; | ||
9208 | - } | ||
9209 | - } | ||
9210 | - | ||
9211 | - return warnings; | ||
9212 | -} | ||
9213 | - | ||
9214 | -static void cleanup(struct objtool_file *file) | ||
9215 | -{ | ||
9216 | - struct instruction *insn, *tmpinsn; | ||
9217 | - struct alternative *alt, *tmpalt; | ||
9218 | - | ||
9219 | - list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) { | ||
9220 | - list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { | ||
9221 | - list_del(&alt->list); | ||
9222 | - free(alt); | ||
9223 | - } | ||
9224 | - list_del(&insn->list); | ||
9225 | - hash_del(&insn->hash); | ||
9226 | - free(insn); | ||
9227 | - } | ||
9228 | - elf_close(file->elf); | ||
9229 | -} | ||
9230 | - | ||
9231 | -const char * const check_usage[] = { | ||
9232 | +static const char * const check_usage[] = { | ||
9233 | "objtool check [<options>] file.o", | ||
9234 | NULL, | ||
9235 | }; | ||
9236 | |||
9237 | +const struct option check_options[] = { | ||
9238 | + OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), | ||
9239 | + OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), | ||
9240 | + OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), | ||
9241 | + OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), | ||
9242 | + OPT_END(), | ||
9243 | +}; | ||
9244 | + | ||
9245 | int cmd_check(int argc, const char **argv) | ||
9246 | { | ||
9247 | - struct objtool_file file; | ||
9248 | - int ret, warnings = 0; | ||
9249 | - | ||
9250 | - const struct option options[] = { | ||
9251 | - OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"), | ||
9252 | - OPT_END(), | ||
9253 | - }; | ||
9254 | + const char *objname; | ||
9255 | |||
9256 | - argc = parse_options(argc, argv, options, check_usage, 0); | ||
9257 | + argc = parse_options(argc, argv, check_options, check_usage, 0); | ||
9258 | |||
9259 | if (argc != 1) | ||
9260 | - usage_with_options(check_usage, options); | ||
9261 | + usage_with_options(check_usage, check_options); | ||
9262 | |||
9263 | objname = argv[0]; | ||
9264 | |||
9265 | - file.elf = elf_open(objname); | ||
9266 | - if (!file.elf) { | ||
9267 | - fprintf(stderr, "error reading elf file %s\n", objname); | ||
9268 | - return 1; | ||
9269 | - } | ||
9270 | - | ||
9271 | - INIT_LIST_HEAD(&file.insn_list); | ||
9272 | - hash_init(file.insn_hash); | ||
9273 | - file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); | ||
9274 | - file.rodata = find_section_by_name(file.elf, ".rodata"); | ||
9275 | - file.ignore_unreachables = false; | ||
9276 | - file.c_file = find_section_by_name(file.elf, ".comment"); | ||
9277 | - | ||
9278 | - ret = decode_sections(&file); | ||
9279 | - if (ret < 0) | ||
9280 | - goto out; | ||
9281 | - warnings += ret; | ||
9282 | - | ||
9283 | - ret = validate_functions(&file); | ||
9284 | - if (ret < 0) | ||
9285 | - goto out; | ||
9286 | - warnings += ret; | ||
9287 | - | ||
9288 | - ret = validate_uncallable_instructions(&file); | ||
9289 | - if (ret < 0) | ||
9290 | - goto out; | ||
9291 | - warnings += ret; | ||
9292 | - | ||
9293 | -out: | ||
9294 | - cleanup(&file); | ||
9295 | - | ||
9296 | - /* ignore warnings for now until we get all the code cleaned up */ | ||
9297 | - if (ret || warnings) | ||
9298 | - return 0; | ||
9299 | - return 0; | ||
9300 | + return check(objname, false); | ||
9301 | } | ||
9302 | diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c | ||
9303 | new file mode 100644 | ||
9304 | index 000000000000..77ea2b97117d | ||
9305 | --- /dev/null | ||
9306 | +++ b/tools/objtool/builtin-orc.c | ||
9307 | @@ -0,0 +1,68 @@ | ||
9308 | +/* | ||
9309 | + * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
9310 | + * | ||
9311 | + * This program is free software; you can redistribute it and/or | ||
9312 | + * modify it under the terms of the GNU General Public License | ||
9313 | + * as published by the Free Software Foundation; either version 2 | ||
9314 | + * of the License, or (at your option) any later version. | ||
9315 | + * | ||
9316 | + * This program is distributed in the hope that it will be useful, | ||
9317 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9318 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9319 | + * GNU General Public License for more details. | ||
9320 | + * | ||
9321 | + * You should have received a copy of the GNU General Public License | ||
9322 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
9323 | + */ | ||
9324 | + | ||
9325 | +/* | ||
9326 | + * objtool orc: | ||
9327 | + * | ||
9328 | + * This command analyzes a .o file and adds .orc_unwind and .orc_unwind_ip | ||
9329 | + * sections to it, which is used by the in-kernel ORC unwinder. | ||
9330 | + * | ||
9331 | + * This command is a superset of "objtool check". | ||
9332 | + */ | ||
9333 | + | ||
9334 | +#include <string.h> | ||
9335 | +#include "builtin.h" | ||
9336 | +#include "check.h" | ||
9337 | + | ||
9338 | + | ||
9339 | +static const char *orc_usage[] = { | ||
9340 | + "objtool orc generate [<options>] file.o", | ||
9341 | + "objtool orc dump file.o", | ||
9342 | + NULL, | ||
9343 | +}; | ||
9344 | + | ||
9345 | +int cmd_orc(int argc, const char **argv) | ||
9346 | +{ | ||
9347 | + const char *objname; | ||
9348 | + | ||
9349 | + argc--; argv++; | ||
9350 | + if (argc <= 0) | ||
9351 | + usage_with_options(orc_usage, check_options); | ||
9352 | + | ||
9353 | + if (!strncmp(argv[0], "gen", 3)) { | ||
9354 | + argc = parse_options(argc, argv, check_options, orc_usage, 0); | ||
9355 | + if (argc != 1) | ||
9356 | + usage_with_options(orc_usage, check_options); | ||
9357 | + | ||
9358 | + objname = argv[0]; | ||
9359 | + | ||
9360 | + return check(objname, true); | ||
9361 | + } | ||
9362 | + | ||
9363 | + if (!strcmp(argv[0], "dump")) { | ||
9364 | + if (argc != 2) | ||
9365 | + usage_with_options(orc_usage, check_options); | ||
9366 | + | ||
9367 | + objname = argv[1]; | ||
9368 | + | ||
9369 | + return orc_dump(objname); | ||
9370 | + } | ||
9371 | + | ||
9372 | + usage_with_options(orc_usage, check_options); | ||
9373 | + | ||
9374 | + return 0; | ||
9375 | +} | ||
9376 | diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h | ||
9377 | index 34d2ba78a616..28ff40e19a14 100644 | ||
9378 | --- a/tools/objtool/builtin.h | ||
9379 | +++ b/tools/objtool/builtin.h | ||
9380 | @@ -17,6 +17,12 @@ | ||
9381 | #ifndef _BUILTIN_H | ||
9382 | #define _BUILTIN_H | ||
9383 | |||
9384 | +#include <subcmd/parse-options.h> | ||
9385 | + | ||
9386 | +extern const struct option check_options[]; | ||
9387 | +extern bool no_fp, no_unreachable, retpoline, module; | ||
9388 | + | ||
9389 | extern int cmd_check(int argc, const char **argv); | ||
9390 | +extern int cmd_orc(int argc, const char **argv); | ||
9391 | |||
9392 | #endif /* _BUILTIN_H */ | ||
9393 | diff --git a/tools/objtool/cfi.h b/tools/objtool/cfi.h | ||
9394 | new file mode 100644 | ||
9395 | index 000000000000..2fe883c665c7 | ||
9396 | --- /dev/null | ||
9397 | +++ b/tools/objtool/cfi.h | ||
9398 | @@ -0,0 +1,55 @@ | ||
9399 | +/* | ||
9400 | + * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
9401 | + * | ||
9402 | + * This program is free software; you can redistribute it and/or | ||
9403 | + * modify it under the terms of the GNU General Public License | ||
9404 | + * as published by the Free Software Foundation; either version 2 | ||
9405 | + * of the License, or (at your option) any later version. | ||
9406 | + * | ||
9407 | + * This program is distributed in the hope that it will be useful, | ||
9408 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9409 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9410 | + * GNU General Public License for more details. | ||
9411 | + * | ||
9412 | + * You should have received a copy of the GNU General Public License | ||
9413 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
9414 | + */ | ||
9415 | + | ||
9416 | +#ifndef _OBJTOOL_CFI_H | ||
9417 | +#define _OBJTOOL_CFI_H | ||
9418 | + | ||
9419 | +#define CFI_UNDEFINED -1 | ||
9420 | +#define CFI_CFA -2 | ||
9421 | +#define CFI_SP_INDIRECT -3 | ||
9422 | +#define CFI_BP_INDIRECT -4 | ||
9423 | + | ||
9424 | +#define CFI_AX 0 | ||
9425 | +#define CFI_DX 1 | ||
9426 | +#define CFI_CX 2 | ||
9427 | +#define CFI_BX 3 | ||
9428 | +#define CFI_SI 4 | ||
9429 | +#define CFI_DI 5 | ||
9430 | +#define CFI_BP 6 | ||
9431 | +#define CFI_SP 7 | ||
9432 | +#define CFI_R8 8 | ||
9433 | +#define CFI_R9 9 | ||
9434 | +#define CFI_R10 10 | ||
9435 | +#define CFI_R11 11 | ||
9436 | +#define CFI_R12 12 | ||
9437 | +#define CFI_R13 13 | ||
9438 | +#define CFI_R14 14 | ||
9439 | +#define CFI_R15 15 | ||
9440 | +#define CFI_RA 16 | ||
9441 | +#define CFI_NUM_REGS 17 | ||
9442 | + | ||
9443 | +struct cfi_reg { | ||
9444 | + int base; | ||
9445 | + int offset; | ||
9446 | +}; | ||
9447 | + | ||
9448 | +struct cfi_state { | ||
9449 | + struct cfi_reg cfa; | ||
9450 | + struct cfi_reg regs[CFI_NUM_REGS]; | ||
9451 | +}; | ||
9452 | + | ||
9453 | +#endif /* _OBJTOOL_CFI_H */ | ||
9454 | diff --git a/tools/objtool/check.c b/tools/objtool/check.c | ||
9455 | new file mode 100644 | ||
9456 | index 000000000000..e128d1c71c30 | ||
9457 | --- /dev/null | ||
9458 | +++ b/tools/objtool/check.c | ||
9459 | @@ -0,0 +1,2209 @@ | ||
9460 | +/* | ||
9461 | + * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
9462 | + * | ||
9463 | + * This program is free software; you can redistribute it and/or | ||
9464 | + * modify it under the terms of the GNU General Public License | ||
9465 | + * as published by the Free Software Foundation; either version 2 | ||
9466 | + * of the License, or (at your option) any later version. | ||
9467 | + * | ||
9468 | + * This program is distributed in the hope that it will be useful, | ||
9469 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9470 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9471 | + * GNU General Public License for more details. | ||
9472 | + * | ||
9473 | + * You should have received a copy of the GNU General Public License | ||
9474 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
9475 | + */ | ||
9476 | + | ||
9477 | +#include <string.h> | ||
9478 | +#include <stdlib.h> | ||
9479 | + | ||
9480 | +#include "builtin.h" | ||
9481 | +#include "check.h" | ||
9482 | +#include "elf.h" | ||
9483 | +#include "special.h" | ||
9484 | +#include "arch.h" | ||
9485 | +#include "warn.h" | ||
9486 | + | ||
9487 | +#include <linux/hashtable.h> | ||
9488 | +#include <linux/kernel.h> | ||
9489 | + | ||
9490 | +struct alternative { | ||
9491 | + struct list_head list; | ||
9492 | + struct instruction *insn; | ||
9493 | +}; | ||
9494 | + | ||
9495 | +const char *objname; | ||
9496 | +struct cfi_state initial_func_cfi; | ||
9497 | + | ||
9498 | +struct instruction *find_insn(struct objtool_file *file, | ||
9499 | + struct section *sec, unsigned long offset) | ||
9500 | +{ | ||
9501 | + struct instruction *insn; | ||
9502 | + | ||
9503 | + hash_for_each_possible(file->insn_hash, insn, hash, offset) | ||
9504 | + if (insn->sec == sec && insn->offset == offset) | ||
9505 | + return insn; | ||
9506 | + | ||
9507 | + return NULL; | ||
9508 | +} | ||
9509 | + | ||
9510 | +static struct instruction *next_insn_same_sec(struct objtool_file *file, | ||
9511 | + struct instruction *insn) | ||
9512 | +{ | ||
9513 | + struct instruction *next = list_next_entry(insn, list); | ||
9514 | + | ||
9515 | + if (!next || &next->list == &file->insn_list || next->sec != insn->sec) | ||
9516 | + return NULL; | ||
9517 | + | ||
9518 | + return next; | ||
9519 | +} | ||
9520 | + | ||
9521 | +static struct instruction *next_insn_same_func(struct objtool_file *file, | ||
9522 | + struct instruction *insn) | ||
9523 | +{ | ||
9524 | + struct instruction *next = list_next_entry(insn, list); | ||
9525 | + struct symbol *func = insn->func; | ||
9526 | + | ||
9527 | + if (!func) | ||
9528 | + return NULL; | ||
9529 | + | ||
9530 | + if (&next->list != &file->insn_list && next->func == func) | ||
9531 | + return next; | ||
9532 | + | ||
9533 | + /* Check if we're already in the subfunction: */ | ||
9534 | + if (func == func->cfunc) | ||
9535 | + return NULL; | ||
9536 | + | ||
9537 | + /* Move to the subfunction: */ | ||
9538 | + return find_insn(file, func->cfunc->sec, func->cfunc->offset); | ||
9539 | +} | ||
9540 | + | ||
9541 | +#define func_for_each_insn_all(file, func, insn) \ | ||
9542 | + for (insn = find_insn(file, func->sec, func->offset); \ | ||
9543 | + insn; \ | ||
9544 | + insn = next_insn_same_func(file, insn)) | ||
9545 | + | ||
9546 | +#define func_for_each_insn(file, func, insn) \ | ||
9547 | + for (insn = find_insn(file, func->sec, func->offset); \ | ||
9548 | + insn && &insn->list != &file->insn_list && \ | ||
9549 | + insn->sec == func->sec && \ | ||
9550 | + insn->offset < func->offset + func->len; \ | ||
9551 | + insn = list_next_entry(insn, list)) | ||
9552 | + | ||
9553 | +#define func_for_each_insn_continue_reverse(file, func, insn) \ | ||
9554 | + for (insn = list_prev_entry(insn, list); \ | ||
9555 | + &insn->list != &file->insn_list && \ | ||
9556 | + insn->sec == func->sec && insn->offset >= func->offset; \ | ||
9557 | + insn = list_prev_entry(insn, list)) | ||
9558 | + | ||
9559 | +#define sec_for_each_insn_from(file, insn) \ | ||
9560 | + for (; insn; insn = next_insn_same_sec(file, insn)) | ||
9561 | + | ||
9562 | +#define sec_for_each_insn_continue(file, insn) \ | ||
9563 | + for (insn = next_insn_same_sec(file, insn); insn; \ | ||
9564 | + insn = next_insn_same_sec(file, insn)) | ||
9565 | + | ||
9566 | +/* | ||
9567 | + * Check if the function has been manually whitelisted with the | ||
9568 | + * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted | ||
9569 | + * due to its use of a context switching instruction. | ||
9570 | + */ | ||
9571 | +static bool ignore_func(struct objtool_file *file, struct symbol *func) | ||
9572 | +{ | ||
9573 | + struct rela *rela; | ||
9574 | + | ||
9575 | + /* check for STACK_FRAME_NON_STANDARD */ | ||
9576 | + if (file->whitelist && file->whitelist->rela) | ||
9577 | + list_for_each_entry(rela, &file->whitelist->rela->rela_list, list) { | ||
9578 | + if (rela->sym->type == STT_SECTION && | ||
9579 | + rela->sym->sec == func->sec && | ||
9580 | + rela->addend == func->offset) | ||
9581 | + return true; | ||
9582 | + if (rela->sym->type == STT_FUNC && rela->sym == func) | ||
9583 | + return true; | ||
9584 | + } | ||
9585 | + | ||
9586 | + return false; | ||
9587 | +} | ||
9588 | + | ||
9589 | +/* | ||
9590 | + * This checks to see if the given function is a "noreturn" function. | ||
9591 | + * | ||
9592 | + * For global functions which are outside the scope of this object file, we | ||
9593 | + * have to keep a manual list of them. | ||
9594 | + * | ||
9595 | + * For local functions, we have to detect them manually by simply looking for | ||
9596 | + * the lack of a return instruction. | ||
9597 | + * | ||
9598 | + * Returns: | ||
9599 | + * -1: error | ||
9600 | + * 0: no dead end | ||
9601 | + * 1: dead end | ||
9602 | + */ | ||
9603 | +static int __dead_end_function(struct objtool_file *file, struct symbol *func, | ||
9604 | + int recursion) | ||
9605 | +{ | ||
9606 | + int i; | ||
9607 | + struct instruction *insn; | ||
9608 | + bool empty = true; | ||
9609 | + | ||
9610 | + /* | ||
9611 | + * Unfortunately these have to be hard coded because the noreturn | ||
9612 | + * attribute isn't provided in ELF data. | ||
9613 | + */ | ||
9614 | + static const char * const global_noreturns[] = { | ||
9615 | + "__stack_chk_fail", | ||
9616 | + "panic", | ||
9617 | + "do_exit", | ||
9618 | + "do_task_dead", | ||
9619 | + "__module_put_and_exit", | ||
9620 | + "complete_and_exit", | ||
9621 | + "kvm_spurious_fault", | ||
9622 | + "__reiserfs_panic", | ||
9623 | + "lbug_with_loc", | ||
9624 | + "fortify_panic", | ||
9625 | + }; | ||
9626 | + | ||
9627 | + if (func->bind == STB_WEAK) | ||
9628 | + return 0; | ||
9629 | + | ||
9630 | + if (func->bind == STB_GLOBAL) | ||
9631 | + for (i = 0; i < ARRAY_SIZE(global_noreturns); i++) | ||
9632 | + if (!strcmp(func->name, global_noreturns[i])) | ||
9633 | + return 1; | ||
9634 | + | ||
9635 | + if (!func->len) | ||
9636 | + return 0; | ||
9637 | + | ||
9638 | + insn = find_insn(file, func->sec, func->offset); | ||
9639 | + if (!insn->func) | ||
9640 | + return 0; | ||
9641 | + | ||
9642 | + func_for_each_insn_all(file, func, insn) { | ||
9643 | + empty = false; | ||
9644 | + | ||
9645 | + if (insn->type == INSN_RETURN) | ||
9646 | + return 0; | ||
9647 | + } | ||
9648 | + | ||
9649 | + if (empty) | ||
9650 | + return 0; | ||
9651 | + | ||
9652 | + /* | ||
9653 | + * A function can have a sibling call instead of a return. In that | ||
9654 | + * case, the function's dead-end status depends on whether the target | ||
9655 | + * of the sibling call returns. | ||
9656 | + */ | ||
9657 | + func_for_each_insn_all(file, func, insn) { | ||
9658 | + if (insn->type == INSN_JUMP_UNCONDITIONAL) { | ||
9659 | + struct instruction *dest = insn->jump_dest; | ||
9660 | + | ||
9661 | + if (!dest) | ||
9662 | + /* sibling call to another file */ | ||
9663 | + return 0; | ||
9664 | + | ||
9665 | + if (dest->func && dest->func->pfunc != insn->func->pfunc) { | ||
9666 | + | ||
9667 | + /* local sibling call */ | ||
9668 | + if (recursion == 5) { | ||
9669 | + /* | ||
9670 | + * Infinite recursion: two functions | ||
9671 | + * have sibling calls to each other. | ||
9672 | + * This is a very rare case. It means | ||
9673 | + * they aren't dead ends. | ||
9674 | + */ | ||
9675 | + return 0; | ||
9676 | + } | ||
9677 | + | ||
9678 | + return __dead_end_function(file, dest->func, | ||
9679 | + recursion + 1); | ||
9680 | + } | ||
9681 | + } | ||
9682 | + | ||
9683 | + if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts)) | ||
9684 | + /* sibling call */ | ||
9685 | + return 0; | ||
9686 | + } | ||
9687 | + | ||
9688 | + return 1; | ||
9689 | +} | ||
9690 | + | ||
9691 | +static int dead_end_function(struct objtool_file *file, struct symbol *func) | ||
9692 | +{ | ||
9693 | + return __dead_end_function(file, func, 0); | ||
9694 | +} | ||
9695 | + | ||
9696 | +static void clear_insn_state(struct insn_state *state) | ||
9697 | +{ | ||
9698 | + int i; | ||
9699 | + | ||
9700 | + memset(state, 0, sizeof(*state)); | ||
9701 | + state->cfa.base = CFI_UNDEFINED; | ||
9702 | + for (i = 0; i < CFI_NUM_REGS; i++) { | ||
9703 | + state->regs[i].base = CFI_UNDEFINED; | ||
9704 | + state->vals[i].base = CFI_UNDEFINED; | ||
9705 | + } | ||
9706 | + state->drap_reg = CFI_UNDEFINED; | ||
9707 | + state->drap_offset = -1; | ||
9708 | +} | ||
9709 | + | ||
9710 | +/* | ||
9711 | + * Call the arch-specific instruction decoder for all the instructions and add | ||
9712 | + * them to the global instruction list. | ||
9713 | + */ | ||
9714 | +static int decode_instructions(struct objtool_file *file) | ||
9715 | +{ | ||
9716 | + struct section *sec; | ||
9717 | + struct symbol *func; | ||
9718 | + unsigned long offset; | ||
9719 | + struct instruction *insn; | ||
9720 | + int ret; | ||
9721 | + | ||
9722 | + for_each_sec(file, sec) { | ||
9723 | + | ||
9724 | + if (!(sec->sh.sh_flags & SHF_EXECINSTR)) | ||
9725 | + continue; | ||
9726 | + | ||
9727 | + if (strcmp(sec->name, ".altinstr_replacement") && | ||
9728 | + strcmp(sec->name, ".altinstr_aux") && | ||
9729 | + strncmp(sec->name, ".discard.", 9)) | ||
9730 | + sec->text = true; | ||
9731 | + | ||
9732 | + for (offset = 0; offset < sec->len; offset += insn->len) { | ||
9733 | + insn = malloc(sizeof(*insn)); | ||
9734 | + if (!insn) { | ||
9735 | + WARN("malloc failed"); | ||
9736 | + return -1; | ||
9737 | + } | ||
9738 | + memset(insn, 0, sizeof(*insn)); | ||
9739 | + INIT_LIST_HEAD(&insn->alts); | ||
9740 | + clear_insn_state(&insn->state); | ||
9741 | + | ||
9742 | + insn->sec = sec; | ||
9743 | + insn->offset = offset; | ||
9744 | + | ||
9745 | + ret = arch_decode_instruction(file->elf, sec, offset, | ||
9746 | + sec->len - offset, | ||
9747 | + &insn->len, &insn->type, | ||
9748 | + &insn->immediate, | ||
9749 | + &insn->stack_op); | ||
9750 | + if (ret) | ||
9751 | + goto err; | ||
9752 | + | ||
9753 | + if (!insn->type || insn->type > INSN_LAST) { | ||
9754 | + WARN_FUNC("invalid instruction type %d", | ||
9755 | + insn->sec, insn->offset, insn->type); | ||
9756 | + ret = -1; | ||
9757 | + goto err; | ||
9758 | + } | ||
9759 | + | ||
9760 | + hash_add(file->insn_hash, &insn->hash, insn->offset); | ||
9761 | + list_add_tail(&insn->list, &file->insn_list); | ||
9762 | + } | ||
9763 | + | ||
9764 | + list_for_each_entry(func, &sec->symbol_list, list) { | ||
9765 | + if (func->type != STT_FUNC) | ||
9766 | + continue; | ||
9767 | + | ||
9768 | + if (!find_insn(file, sec, func->offset)) { | ||
9769 | + WARN("%s(): can't find starting instruction", | ||
9770 | + func->name); | ||
9771 | + return -1; | ||
9772 | + } | ||
9773 | + | ||
9774 | + func_for_each_insn(file, func, insn) | ||
9775 | + if (!insn->func) | ||
9776 | + insn->func = func; | ||
9777 | + } | ||
9778 | + } | ||
9779 | + | ||
9780 | + return 0; | ||
9781 | + | ||
9782 | +err: | ||
9783 | + free(insn); | ||
9784 | + return ret; | ||
9785 | +} | ||
9786 | + | ||
9787 | +/* | ||
9788 | + * Mark "ud2" instructions and manually annotated dead ends. | ||
9789 | + */ | ||
9790 | +static int add_dead_ends(struct objtool_file *file) | ||
9791 | +{ | ||
9792 | + struct section *sec; | ||
9793 | + struct rela *rela; | ||
9794 | + struct instruction *insn; | ||
9795 | + bool found; | ||
9796 | + | ||
9797 | + /* | ||
9798 | + * By default, "ud2" is a dead end unless otherwise annotated, because | ||
9799 | + * GCC 7 inserts it for certain divide-by-zero cases. | ||
9800 | + */ | ||
9801 | + for_each_insn(file, insn) | ||
9802 | + if (insn->type == INSN_BUG) | ||
9803 | + insn->dead_end = true; | ||
9804 | + | ||
9805 | + /* | ||
9806 | + * Check for manually annotated dead ends. | ||
9807 | + */ | ||
9808 | + sec = find_section_by_name(file->elf, ".rela.discard.unreachable"); | ||
9809 | + if (!sec) | ||
9810 | + goto reachable; | ||
9811 | + | ||
9812 | + list_for_each_entry(rela, &sec->rela_list, list) { | ||
9813 | + if (rela->sym->type != STT_SECTION) { | ||
9814 | + WARN("unexpected relocation symbol type in %s", sec->name); | ||
9815 | + return -1; | ||
9816 | + } | ||
9817 | + insn = find_insn(file, rela->sym->sec, rela->addend); | ||
9818 | + if (insn) | ||
9819 | + insn = list_prev_entry(insn, list); | ||
9820 | + else if (rela->addend == rela->sym->sec->len) { | ||
9821 | + found = false; | ||
9822 | + list_for_each_entry_reverse(insn, &file->insn_list, list) { | ||
9823 | + if (insn->sec == rela->sym->sec) { | ||
9824 | + found = true; | ||
9825 | + break; | ||
9826 | + } | ||
9827 | + } | ||
9828 | + | ||
9829 | + if (!found) { | ||
9830 | + WARN("can't find unreachable insn at %s+0x%x", | ||
9831 | + rela->sym->sec->name, rela->addend); | ||
9832 | + return -1; | ||
9833 | + } | ||
9834 | + } else { | ||
9835 | + WARN("can't find unreachable insn at %s+0x%x", | ||
9836 | + rela->sym->sec->name, rela->addend); | ||
9837 | + return -1; | ||
9838 | + } | ||
9839 | + | ||
9840 | + insn->dead_end = true; | ||
9841 | + } | ||
9842 | + | ||
9843 | +reachable: | ||
9844 | + /* | ||
9845 | + * These manually annotated reachable checks are needed for GCC 4.4, | ||
9846 | + * where the Linux unreachable() macro isn't supported. In that case | ||
9847 | + * GCC doesn't know the "ud2" is fatal, so it generates code as if it's | ||
9848 | + * not a dead end. | ||
9849 | + */ | ||
9850 | + sec = find_section_by_name(file->elf, ".rela.discard.reachable"); | ||
9851 | + if (!sec) | ||
9852 | + return 0; | ||
9853 | + | ||
9854 | + list_for_each_entry(rela, &sec->rela_list, list) { | ||
9855 | + if (rela->sym->type != STT_SECTION) { | ||
9856 | + WARN("unexpected relocation symbol type in %s", sec->name); | ||
9857 | + return -1; | ||
9858 | + } | ||
9859 | + insn = find_insn(file, rela->sym->sec, rela->addend); | ||
9860 | + if (insn) | ||
9861 | + insn = list_prev_entry(insn, list); | ||
9862 | + else if (rela->addend == rela->sym->sec->len) { | ||
9863 | + found = false; | ||
9864 | + list_for_each_entry_reverse(insn, &file->insn_list, list) { | ||
9865 | + if (insn->sec == rela->sym->sec) { | ||
9866 | + found = true; | ||
9867 | + break; | ||
9868 | + } | ||
9869 | + } | ||
9870 | + | ||
9871 | + if (!found) { | ||
9872 | + WARN("can't find reachable insn at %s+0x%x", | ||
9873 | + rela->sym->sec->name, rela->addend); | ||
9874 | + return -1; | ||
9875 | + } | ||
9876 | + } else { | ||
9877 | + WARN("can't find reachable insn at %s+0x%x", | ||
9878 | + rela->sym->sec->name, rela->addend); | ||
9879 | + return -1; | ||
9880 | + } | ||
9881 | + | ||
9882 | + insn->dead_end = false; | ||
9883 | + } | ||
9884 | + | ||
9885 | + return 0; | ||
9886 | +} | ||
9887 | + | ||
9888 | +/* | ||
9889 | + * Warnings shouldn't be reported for ignored functions. | ||
9890 | + */ | ||
9891 | +static void add_ignores(struct objtool_file *file) | ||
9892 | +{ | ||
9893 | + struct instruction *insn; | ||
9894 | + struct section *sec; | ||
9895 | + struct symbol *func; | ||
9896 | + | ||
9897 | + for_each_sec(file, sec) { | ||
9898 | + list_for_each_entry(func, &sec->symbol_list, list) { | ||
9899 | + if (func->type != STT_FUNC) | ||
9900 | + continue; | ||
9901 | + | ||
9902 | + if (!ignore_func(file, func)) | ||
9903 | + continue; | ||
9904 | + | ||
9905 | + func_for_each_insn_all(file, func, insn) | ||
9906 | + insn->ignore = true; | ||
9907 | + } | ||
9908 | + } | ||
9909 | +} | ||
9910 | + | ||
9911 | +/* | ||
9912 | + * FIXME: For now, just ignore any alternatives which add retpolines. This is | ||
9913 | + * a temporary hack, as it doesn't allow ORC to unwind from inside a retpoline. | ||
9914 | + * But it at least allows objtool to understand the control flow *around* the | ||
9915 | + * retpoline. | ||
9916 | + */ | ||
9917 | +static int add_nospec_ignores(struct objtool_file *file) | ||
9918 | +{ | ||
9919 | + struct section *sec; | ||
9920 | + struct rela *rela; | ||
9921 | + struct instruction *insn; | ||
9922 | + | ||
9923 | + sec = find_section_by_name(file->elf, ".rela.discard.nospec"); | ||
9924 | + if (!sec) | ||
9925 | + return 0; | ||
9926 | + | ||
9927 | + list_for_each_entry(rela, &sec->rela_list, list) { | ||
9928 | + if (rela->sym->type != STT_SECTION) { | ||
9929 | + WARN("unexpected relocation symbol type in %s", sec->name); | ||
9930 | + return -1; | ||
9931 | + } | ||
9932 | + | ||
9933 | + insn = find_insn(file, rela->sym->sec, rela->addend); | ||
9934 | + if (!insn) { | ||
9935 | + WARN("bad .discard.nospec entry"); | ||
9936 | + return -1; | ||
9937 | + } | ||
9938 | + | ||
9939 | + insn->ignore_alts = true; | ||
9940 | + } | ||
9941 | + | ||
9942 | + return 0; | ||
9943 | +} | ||
9944 | + | ||
9945 | +/* | ||
9946 | + * Find the destination instructions for all jumps. | ||
9947 | + */ | ||
9948 | +static int add_jump_destinations(struct objtool_file *file) | ||
9949 | +{ | ||
9950 | + struct instruction *insn; | ||
9951 | + struct rela *rela; | ||
9952 | + struct section *dest_sec; | ||
9953 | + unsigned long dest_off; | ||
9954 | + | ||
9955 | + for_each_insn(file, insn) { | ||
9956 | + if (insn->type != INSN_JUMP_CONDITIONAL && | ||
9957 | + insn->type != INSN_JUMP_UNCONDITIONAL) | ||
9958 | + continue; | ||
9959 | + | ||
9960 | + if (insn->ignore) | ||
9961 | + continue; | ||
9962 | + | ||
9963 | + rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
9964 | + insn->len); | ||
9965 | + if (!rela) { | ||
9966 | + dest_sec = insn->sec; | ||
9967 | + dest_off = insn->offset + insn->len + insn->immediate; | ||
9968 | + } else if (rela->sym->type == STT_SECTION) { | ||
9969 | + dest_sec = rela->sym->sec; | ||
9970 | + dest_off = rela->addend + 4; | ||
9971 | + } else if (rela->sym->sec->idx) { | ||
9972 | + dest_sec = rela->sym->sec; | ||
9973 | + dest_off = rela->sym->sym.st_value + rela->addend + 4; | ||
9974 | + } else if (strstr(rela->sym->name, "_indirect_thunk_")) { | ||
9975 | + /* | ||
9976 | + * Retpoline jumps are really dynamic jumps in | ||
9977 | + * disguise, so convert them accordingly. | ||
9978 | + */ | ||
9979 | + insn->type = INSN_JUMP_DYNAMIC; | ||
9980 | + insn->retpoline_safe = true; | ||
9981 | + continue; | ||
9982 | + } else { | ||
9983 | + /* sibling call */ | ||
9984 | + insn->jump_dest = 0; | ||
9985 | + continue; | ||
9986 | + } | ||
9987 | + | ||
9988 | + insn->jump_dest = find_insn(file, dest_sec, dest_off); | ||
9989 | + if (!insn->jump_dest) { | ||
9990 | + | ||
9991 | + /* | ||
9992 | + * This is a special case where an alt instruction | ||
9993 | + * jumps past the end of the section. These are | ||
9994 | + * handled later in handle_group_alt(). | ||
9995 | + */ | ||
9996 | + if (!strcmp(insn->sec->name, ".altinstr_replacement")) | ||
9997 | + continue; | ||
9998 | + | ||
9999 | + WARN_FUNC("can't find jump dest instruction at %s+0x%lx", | ||
10000 | + insn->sec, insn->offset, dest_sec->name, | ||
10001 | + dest_off); | ||
10002 | + return -1; | ||
10003 | + } | ||
10004 | + } | ||
10005 | + | ||
10006 | + return 0; | ||
10007 | +} | ||
10008 | + | ||
10009 | +/* | ||
10010 | + * Find the destination instructions for all calls. | ||
10011 | + */ | ||
10012 | +static int add_call_destinations(struct objtool_file *file) | ||
10013 | +{ | ||
10014 | + struct instruction *insn; | ||
10015 | + unsigned long dest_off; | ||
10016 | + struct rela *rela; | ||
10017 | + | ||
10018 | + for_each_insn(file, insn) { | ||
10019 | + if (insn->type != INSN_CALL) | ||
10020 | + continue; | ||
10021 | + | ||
10022 | + rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
10023 | + insn->len); | ||
10024 | + if (!rela) { | ||
10025 | + dest_off = insn->offset + insn->len + insn->immediate; | ||
10026 | + insn->call_dest = find_symbol_by_offset(insn->sec, | ||
10027 | + dest_off); | ||
10028 | + | ||
10029 | + if (!insn->call_dest && !insn->ignore) { | ||
10030 | + WARN_FUNC("unsupported intra-function call", | ||
10031 | + insn->sec, insn->offset); | ||
10032 | + if (retpoline) | ||
10033 | + WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); | ||
10034 | + return -1; | ||
10035 | + } | ||
10036 | + | ||
10037 | + } else if (rela->sym->type == STT_SECTION) { | ||
10038 | + insn->call_dest = find_symbol_by_offset(rela->sym->sec, | ||
10039 | + rela->addend+4); | ||
10040 | + if (!insn->call_dest || | ||
10041 | + insn->call_dest->type != STT_FUNC) { | ||
10042 | + WARN_FUNC("can't find call dest symbol at %s+0x%x", | ||
10043 | + insn->sec, insn->offset, | ||
10044 | + rela->sym->sec->name, | ||
10045 | + rela->addend + 4); | ||
10046 | + return -1; | ||
10047 | + } | ||
10048 | + } else | ||
10049 | + insn->call_dest = rela->sym; | ||
10050 | + } | ||
10051 | + | ||
10052 | + return 0; | ||
10053 | +} | ||
10054 | + | ||
10055 | +/* | ||
10056 | + * The .alternatives section requires some extra special care, over and above | ||
10057 | + * what other special sections require: | ||
10058 | + * | ||
10059 | + * 1. Because alternatives are patched in-place, we need to insert a fake jump | ||
10060 | + * instruction at the end so that validate_branch() skips all the original | ||
10061 | + * replaced instructions when validating the new instruction path. | ||
10062 | + * | ||
10063 | + * 2. An added wrinkle is that the new instruction length might be zero. In | ||
10064 | + * that case the old instructions are replaced with noops. We simulate that | ||
10065 | + * by creating a fake jump as the only new instruction. | ||
10066 | + * | ||
10067 | + * 3. In some cases, the alternative section includes an instruction which | ||
10068 | + * conditionally jumps to the _end_ of the entry. We have to modify these | ||
10069 | + * jumps' destinations to point back to .text rather than the end of the | ||
10070 | + * entry in .altinstr_replacement. | ||
10071 | + * | ||
10072 | + * 4. It has been requested that we don't validate the !POPCNT feature path | ||
10073 | + * which is a "very very small percentage of machines". | ||
10074 | + */ | ||
10075 | +static int handle_group_alt(struct objtool_file *file, | ||
10076 | + struct special_alt *special_alt, | ||
10077 | + struct instruction *orig_insn, | ||
10078 | + struct instruction **new_insn) | ||
10079 | +{ | ||
10080 | + struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL; | ||
10081 | + unsigned long dest_off; | ||
10082 | + | ||
10083 | + last_orig_insn = NULL; | ||
10084 | + insn = orig_insn; | ||
10085 | + sec_for_each_insn_from(file, insn) { | ||
10086 | + if (insn->offset >= special_alt->orig_off + special_alt->orig_len) | ||
10087 | + break; | ||
10088 | + | ||
10089 | + if (special_alt->skip_orig) | ||
10090 | + insn->type = INSN_NOP; | ||
10091 | + | ||
10092 | + insn->alt_group = true; | ||
10093 | + last_orig_insn = insn; | ||
10094 | + } | ||
10095 | + | ||
10096 | + if (next_insn_same_sec(file, last_orig_insn)) { | ||
10097 | + fake_jump = malloc(sizeof(*fake_jump)); | ||
10098 | + if (!fake_jump) { | ||
10099 | + WARN("malloc failed"); | ||
10100 | + return -1; | ||
10101 | + } | ||
10102 | + memset(fake_jump, 0, sizeof(*fake_jump)); | ||
10103 | + INIT_LIST_HEAD(&fake_jump->alts); | ||
10104 | + clear_insn_state(&fake_jump->state); | ||
10105 | + | ||
10106 | + fake_jump->sec = special_alt->new_sec; | ||
10107 | + fake_jump->offset = -1; | ||
10108 | + fake_jump->type = INSN_JUMP_UNCONDITIONAL; | ||
10109 | + fake_jump->jump_dest = list_next_entry(last_orig_insn, list); | ||
10110 | + fake_jump->ignore = true; | ||
10111 | + } | ||
10112 | + | ||
10113 | + if (!special_alt->new_len) { | ||
10114 | + if (!fake_jump) { | ||
10115 | + WARN("%s: empty alternative at end of section", | ||
10116 | + special_alt->orig_sec->name); | ||
10117 | + return -1; | ||
10118 | + } | ||
10119 | + | ||
10120 | + *new_insn = fake_jump; | ||
10121 | + return 0; | ||
10122 | + } | ||
10123 | + | ||
10124 | + last_new_insn = NULL; | ||
10125 | + insn = *new_insn; | ||
10126 | + sec_for_each_insn_from(file, insn) { | ||
10127 | + if (insn->offset >= special_alt->new_off + special_alt->new_len) | ||
10128 | + break; | ||
10129 | + | ||
10130 | + last_new_insn = insn; | ||
10131 | + | ||
10132 | + insn->ignore = orig_insn->ignore_alts; | ||
10133 | + | ||
10134 | + if (insn->type != INSN_JUMP_CONDITIONAL && | ||
10135 | + insn->type != INSN_JUMP_UNCONDITIONAL) | ||
10136 | + continue; | ||
10137 | + | ||
10138 | + if (!insn->immediate) | ||
10139 | + continue; | ||
10140 | + | ||
10141 | + dest_off = insn->offset + insn->len + insn->immediate; | ||
10142 | + if (dest_off == special_alt->new_off + special_alt->new_len) { | ||
10143 | + if (!fake_jump) { | ||
10144 | + WARN("%s: alternative jump to end of section", | ||
10145 | + special_alt->orig_sec->name); | ||
10146 | + return -1; | ||
10147 | + } | ||
10148 | + insn->jump_dest = fake_jump; | ||
10149 | + } | ||
10150 | + | ||
10151 | + if (!insn->jump_dest) { | ||
10152 | + WARN_FUNC("can't find alternative jump destination", | ||
10153 | + insn->sec, insn->offset); | ||
10154 | + return -1; | ||
10155 | + } | ||
10156 | + } | ||
10157 | + | ||
10158 | + if (!last_new_insn) { | ||
10159 | + WARN_FUNC("can't find last new alternative instruction", | ||
10160 | + special_alt->new_sec, special_alt->new_off); | ||
10161 | + return -1; | ||
10162 | + } | ||
10163 | + | ||
10164 | + if (fake_jump) | ||
10165 | + list_add(&fake_jump->list, &last_new_insn->list); | ||
10166 | + | ||
10167 | + return 0; | ||
10168 | +} | ||
10169 | + | ||
10170 | +/* | ||
10171 | + * A jump table entry can either convert a nop to a jump or a jump to a nop. | ||
10172 | + * If the original instruction is a jump, make the alt entry an effective nop | ||
10173 | + * by just skipping the original instruction. | ||
10174 | + */ | ||
10175 | +static int handle_jump_alt(struct objtool_file *file, | ||
10176 | + struct special_alt *special_alt, | ||
10177 | + struct instruction *orig_insn, | ||
10178 | + struct instruction **new_insn) | ||
10179 | +{ | ||
10180 | + if (orig_insn->type == INSN_NOP) | ||
10181 | + return 0; | ||
10182 | + | ||
10183 | + if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) { | ||
10184 | + WARN_FUNC("unsupported instruction at jump label", | ||
10185 | + orig_insn->sec, orig_insn->offset); | ||
10186 | + return -1; | ||
10187 | + } | ||
10188 | + | ||
10189 | + *new_insn = list_next_entry(orig_insn, list); | ||
10190 | + return 0; | ||
10191 | +} | ||
10192 | + | ||
10193 | +/* | ||
10194 | + * Read all the special sections which have alternate instructions which can be | ||
10195 | + * patched in or redirected to at runtime. Each instruction having alternate | ||
10196 | + * instruction(s) has them added to its insn->alts list, which will be | ||
10197 | + * traversed in validate_branch(). | ||
10198 | + */ | ||
10199 | +static int add_special_section_alts(struct objtool_file *file) | ||
10200 | +{ | ||
10201 | + struct list_head special_alts; | ||
10202 | + struct instruction *orig_insn, *new_insn; | ||
10203 | + struct special_alt *special_alt, *tmp; | ||
10204 | + struct alternative *alt; | ||
10205 | + int ret; | ||
10206 | + | ||
10207 | + ret = special_get_alts(file->elf, &special_alts); | ||
10208 | + if (ret) | ||
10209 | + return ret; | ||
10210 | + | ||
10211 | + list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { | ||
10212 | + | ||
10213 | + orig_insn = find_insn(file, special_alt->orig_sec, | ||
10214 | + special_alt->orig_off); | ||
10215 | + if (!orig_insn) { | ||
10216 | + WARN_FUNC("special: can't find orig instruction", | ||
10217 | + special_alt->orig_sec, special_alt->orig_off); | ||
10218 | + ret = -1; | ||
10219 | + goto out; | ||
10220 | + } | ||
10221 | + | ||
10222 | + new_insn = NULL; | ||
10223 | + if (!special_alt->group || special_alt->new_len) { | ||
10224 | + new_insn = find_insn(file, special_alt->new_sec, | ||
10225 | + special_alt->new_off); | ||
10226 | + if (!new_insn) { | ||
10227 | + WARN_FUNC("special: can't find new instruction", | ||
10228 | + special_alt->new_sec, | ||
10229 | + special_alt->new_off); | ||
10230 | + ret = -1; | ||
10231 | + goto out; | ||
10232 | + } | ||
10233 | + } | ||
10234 | + | ||
10235 | + if (special_alt->group) { | ||
10236 | + ret = handle_group_alt(file, special_alt, orig_insn, | ||
10237 | + &new_insn); | ||
10238 | + if (ret) | ||
10239 | + goto out; | ||
10240 | + } else if (special_alt->jump_or_nop) { | ||
10241 | + ret = handle_jump_alt(file, special_alt, orig_insn, | ||
10242 | + &new_insn); | ||
10243 | + if (ret) | ||
10244 | + goto out; | ||
10245 | + } | ||
10246 | + | ||
10247 | + alt = malloc(sizeof(*alt)); | ||
10248 | + if (!alt) { | ||
10249 | + WARN("malloc failed"); | ||
10250 | + ret = -1; | ||
10251 | + goto out; | ||
10252 | + } | ||
10253 | + | ||
10254 | + alt->insn = new_insn; | ||
10255 | + list_add_tail(&alt->list, &orig_insn->alts); | ||
10256 | + | ||
10257 | + list_del(&special_alt->list); | ||
10258 | + free(special_alt); | ||
10259 | + } | ||
10260 | + | ||
10261 | +out: | ||
10262 | + return ret; | ||
10263 | +} | ||
10264 | + | ||
10265 | +static int add_switch_table(struct objtool_file *file, struct instruction *insn, | ||
10266 | + struct rela *table, struct rela *next_table) | ||
10267 | +{ | ||
10268 | + struct rela *rela = table; | ||
10269 | + struct instruction *alt_insn; | ||
10270 | + struct alternative *alt; | ||
10271 | + struct symbol *pfunc = insn->func->pfunc; | ||
10272 | + unsigned int prev_offset = 0; | ||
10273 | + | ||
10274 | + list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) { | ||
10275 | + if (rela == next_table) | ||
10276 | + break; | ||
10277 | + | ||
10278 | + /* Make sure the switch table entries are consecutive: */ | ||
10279 | + if (prev_offset && rela->offset != prev_offset + 8) | ||
10280 | + break; | ||
10281 | + | ||
10282 | + /* Detect function pointers from contiguous objects: */ | ||
10283 | + if (rela->sym->sec == pfunc->sec && | ||
10284 | + rela->addend == pfunc->offset) | ||
10285 | + break; | ||
10286 | + | ||
10287 | + alt_insn = find_insn(file, rela->sym->sec, rela->addend); | ||
10288 | + if (!alt_insn) | ||
10289 | + break; | ||
10290 | + | ||
10291 | + /* Make sure the jmp dest is in the function or subfunction: */ | ||
10292 | + if (alt_insn->func->pfunc != pfunc) | ||
10293 | + break; | ||
10294 | + | ||
10295 | + alt = malloc(sizeof(*alt)); | ||
10296 | + if (!alt) { | ||
10297 | + WARN("malloc failed"); | ||
10298 | + return -1; | ||
10299 | + } | ||
10300 | + | ||
10301 | + alt->insn = alt_insn; | ||
10302 | + list_add_tail(&alt->list, &insn->alts); | ||
10303 | + prev_offset = rela->offset; | ||
10304 | + } | ||
10305 | + | ||
10306 | + if (!prev_offset) { | ||
10307 | + WARN_FUNC("can't find switch jump table", | ||
10308 | + insn->sec, insn->offset); | ||
10309 | + return -1; | ||
10310 | + } | ||
10311 | + | ||
10312 | + return 0; | ||
10313 | +} | ||
10314 | + | ||
10315 | +/* | ||
10316 | + * find_switch_table() - Given a dynamic jump, find the switch jump table in | ||
10317 | + * .rodata associated with it. | ||
10318 | + * | ||
10319 | + * There are 3 basic patterns: | ||
10320 | + * | ||
10321 | + * 1. jmpq *[rodata addr](,%reg,8) | ||
10322 | + * | ||
10323 | + * This is the most common case by far. It jumps to an address in a simple | ||
10324 | + * jump table which is stored in .rodata. | ||
10325 | + * | ||
10326 | + * 2. jmpq *[rodata addr](%rip) | ||
10327 | + * | ||
10328 | + * This is caused by a rare GCC quirk, currently only seen in three driver | ||
10329 | + * functions in the kernel, only with certain obscure non-distro configs. | ||
10330 | + * | ||
10331 | + * As part of an optimization, GCC makes a copy of an existing switch jump | ||
10332 | + * table, modifies it, and then hard-codes the jump (albeit with an indirect | ||
10333 | + * jump) to use a single entry in the table. The rest of the jump table and | ||
10334 | + * some of its jump targets remain as dead code. | ||
10335 | + * | ||
10336 | + * In such a case we can just crudely ignore all unreachable instruction | ||
10337 | + * warnings for the entire object file. Ideally we would just ignore them | ||
10338 | + * for the function, but that would require redesigning the code quite a | ||
10339 | + * bit. And honestly that's just not worth doing: unreachable instruction | ||
10340 | + * warnings are of questionable value anyway, and this is such a rare issue. | ||
10341 | + * | ||
10342 | + * 3. mov [rodata addr],%reg1 | ||
10343 | + * ... some instructions ... | ||
10344 | + * jmpq *(%reg1,%reg2,8) | ||
10345 | + * | ||
10346 | + * This is a fairly uncommon pattern which is new for GCC 6. As of this | ||
10347 | + * writing, there are 11 occurrences of it in the allmodconfig kernel. | ||
10348 | + * | ||
10349 | + * As of GCC 7 there are quite a few more of these and the 'in between' code | ||
10350 | + * is significant. Esp. with KASAN enabled some of the code between the mov | ||
10351 | + * and jmpq uses .rodata itself, which can confuse things. | ||
10352 | + * | ||
10353 | + * TODO: Once we have DWARF CFI and smarter instruction decoding logic, | ||
10354 | + * ensure the same register is used in the mov and jump instructions. | ||
10355 | + * | ||
10356 | + * NOTE: RETPOLINE made it harder still to decode dynamic jumps. | ||
10357 | + */ | ||
10358 | +static struct rela *find_switch_table(struct objtool_file *file, | ||
10359 | + struct symbol *func, | ||
10360 | + struct instruction *insn) | ||
10361 | +{ | ||
10362 | + struct rela *text_rela, *rodata_rela; | ||
10363 | + struct instruction *orig_insn = insn; | ||
10364 | + unsigned long table_offset; | ||
10365 | + | ||
10366 | + /* | ||
10367 | + * Backward search using the @first_jump_src links, these help avoid | ||
10368 | + * much of the 'in between' code. Which avoids us getting confused by | ||
10369 | + * it. | ||
10370 | + */ | ||
10371 | + for (; | ||
10372 | + &insn->list != &file->insn_list && | ||
10373 | + insn->sec == func->sec && | ||
10374 | + insn->offset >= func->offset; | ||
10375 | + | ||
10376 | + insn = insn->first_jump_src ?: list_prev_entry(insn, list)) { | ||
10377 | + | ||
10378 | + if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC) | ||
10379 | + break; | ||
10380 | + | ||
10381 | + /* allow small jumps within the range */ | ||
10382 | + if (insn->type == INSN_JUMP_UNCONDITIONAL && | ||
10383 | + insn->jump_dest && | ||
10384 | + (insn->jump_dest->offset <= insn->offset || | ||
10385 | + insn->jump_dest->offset > orig_insn->offset)) | ||
10386 | + break; | ||
10387 | + | ||
10388 | + /* look for a relocation which references .rodata */ | ||
10389 | + text_rela = find_rela_by_dest_range(insn->sec, insn->offset, | ||
10390 | + insn->len); | ||
10391 | + if (!text_rela || text_rela->sym != file->rodata->sym) | ||
10392 | + continue; | ||
10393 | + | ||
10394 | + table_offset = text_rela->addend; | ||
10395 | + if (text_rela->type == R_X86_64_PC32) | ||
10396 | + table_offset += 4; | ||
10397 | + | ||
10398 | + /* | ||
10399 | + * Make sure the .rodata address isn't associated with a | ||
10400 | + * symbol. gcc jump tables are anonymous data. | ||
10401 | + */ | ||
10402 | + if (find_symbol_containing(file->rodata, table_offset)) | ||
10403 | + continue; | ||
10404 | + | ||
10405 | + rodata_rela = find_rela_by_dest(file->rodata, table_offset); | ||
10406 | + if (rodata_rela) { | ||
10407 | + /* | ||
10408 | + * Use of RIP-relative switch jumps is quite rare, and | ||
10409 | + * indicates a rare GCC quirk/bug which can leave dead | ||
10410 | + * code behind. | ||
10411 | + */ | ||
10412 | + if (text_rela->type == R_X86_64_PC32) | ||
10413 | + file->ignore_unreachables = true; | ||
10414 | + | ||
10415 | + return rodata_rela; | ||
10416 | + } | ||
10417 | + } | ||
10418 | + | ||
10419 | + return NULL; | ||
10420 | +} | ||
10421 | + | ||
10422 | + | ||
10423 | +static int add_func_switch_tables(struct objtool_file *file, | ||
10424 | + struct symbol *func) | ||
10425 | +{ | ||
10426 | + struct instruction *insn, *last = NULL, *prev_jump = NULL; | ||
10427 | + struct rela *rela, *prev_rela = NULL; | ||
10428 | + int ret; | ||
10429 | + | ||
10430 | + func_for_each_insn_all(file, func, insn) { | ||
10431 | + if (!last) | ||
10432 | + last = insn; | ||
10433 | + | ||
10434 | + /* | ||
10435 | + * Store back-pointers for unconditional forward jumps such | ||
10436 | + * that find_switch_table() can back-track using those and | ||
10437 | + * avoid some potentially confusing code. | ||
10438 | + */ | ||
10439 | + if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && | ||
10440 | + insn->offset > last->offset && | ||
10441 | + insn->jump_dest->offset > insn->offset && | ||
10442 | + !insn->jump_dest->first_jump_src) { | ||
10443 | + | ||
10444 | + insn->jump_dest->first_jump_src = insn; | ||
10445 | + last = insn->jump_dest; | ||
10446 | + } | ||
10447 | + | ||
10448 | + if (insn->type != INSN_JUMP_DYNAMIC) | ||
10449 | + continue; | ||
10450 | + | ||
10451 | + rela = find_switch_table(file, func, insn); | ||
10452 | + if (!rela) | ||
10453 | + continue; | ||
10454 | + | ||
10455 | + /* | ||
10456 | + * We found a switch table, but we don't know yet how big it | ||
10457 | + * is. Don't add it until we reach the end of the function or | ||
10458 | + * the beginning of another switch table in the same function. | ||
10459 | + */ | ||
10460 | + if (prev_jump) { | ||
10461 | + ret = add_switch_table(file, prev_jump, prev_rela, rela); | ||
10462 | + if (ret) | ||
10463 | + return ret; | ||
10464 | + } | ||
10465 | + | ||
10466 | + prev_jump = insn; | ||
10467 | + prev_rela = rela; | ||
10468 | + } | ||
10469 | + | ||
10470 | + if (prev_jump) { | ||
10471 | + ret = add_switch_table(file, prev_jump, prev_rela, NULL); | ||
10472 | + if (ret) | ||
10473 | + return ret; | ||
10474 | + } | ||
10475 | + | ||
10476 | + return 0; | ||
10477 | +} | ||
10478 | + | ||
10479 | +/* | ||
10480 | + * For some switch statements, gcc generates a jump table in the .rodata | ||
10481 | + * section which contains a list of addresses within the function to jump to. | ||
10482 | + * This finds these jump tables and adds them to the insn->alts lists. | ||
10483 | + */ | ||
10484 | +static int add_switch_table_alts(struct objtool_file *file) | ||
10485 | +{ | ||
10486 | + struct section *sec; | ||
10487 | + struct symbol *func; | ||
10488 | + int ret; | ||
10489 | + | ||
10490 | + if (!file->rodata || !file->rodata->rela) | ||
10491 | + return 0; | ||
10492 | + | ||
10493 | + for_each_sec(file, sec) { | ||
10494 | + list_for_each_entry(func, &sec->symbol_list, list) { | ||
10495 | + if (func->type != STT_FUNC) | ||
10496 | + continue; | ||
10497 | + | ||
10498 | + ret = add_func_switch_tables(file, func); | ||
10499 | + if (ret) | ||
10500 | + return ret; | ||
10501 | + } | ||
10502 | + } | ||
10503 | + | ||
10504 | + return 0; | ||
10505 | +} | ||
10506 | + | ||
10507 | +static int read_unwind_hints(struct objtool_file *file) | ||
10508 | +{ | ||
10509 | + struct section *sec, *relasec; | ||
10510 | + struct rela *rela; | ||
10511 | + struct unwind_hint *hint; | ||
10512 | + struct instruction *insn; | ||
10513 | + struct cfi_reg *cfa; | ||
10514 | + int i; | ||
10515 | + | ||
10516 | + sec = find_section_by_name(file->elf, ".discard.unwind_hints"); | ||
10517 | + if (!sec) | ||
10518 | + return 0; | ||
10519 | + | ||
10520 | + relasec = sec->rela; | ||
10521 | + if (!relasec) { | ||
10522 | + WARN("missing .rela.discard.unwind_hints section"); | ||
10523 | + return -1; | ||
10524 | + } | ||
10525 | + | ||
10526 | + if (sec->len % sizeof(struct unwind_hint)) { | ||
10527 | + WARN("struct unwind_hint size mismatch"); | ||
10528 | + return -1; | ||
10529 | + } | ||
10530 | + | ||
10531 | + file->hints = true; | ||
10532 | + | ||
10533 | + for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) { | ||
10534 | + hint = (struct unwind_hint *)sec->data->d_buf + i; | ||
10535 | + | ||
10536 | + rela = find_rela_by_dest(sec, i * sizeof(*hint)); | ||
10537 | + if (!rela) { | ||
10538 | + WARN("can't find rela for unwind_hints[%d]", i); | ||
10539 | + return -1; | ||
10540 | + } | ||
10541 | + | ||
10542 | + insn = find_insn(file, rela->sym->sec, rela->addend); | ||
10543 | + if (!insn) { | ||
10544 | + WARN("can't find insn for unwind_hints[%d]", i); | ||
10545 | + return -1; | ||
10546 | + } | ||
10547 | + | ||
10548 | + cfa = &insn->state.cfa; | ||
10549 | + | ||
10550 | + if (hint->type == UNWIND_HINT_TYPE_SAVE) { | ||
10551 | + insn->save = true; | ||
10552 | + continue; | ||
10553 | + | ||
10554 | + } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) { | ||
10555 | + insn->restore = true; | ||
10556 | + insn->hint = true; | ||
10557 | + continue; | ||
10558 | + } | ||
10559 | + | ||
10560 | + insn->hint = true; | ||
10561 | + | ||
10562 | + switch (hint->sp_reg) { | ||
10563 | + case ORC_REG_UNDEFINED: | ||
10564 | + cfa->base = CFI_UNDEFINED; | ||
10565 | + break; | ||
10566 | + case ORC_REG_SP: | ||
10567 | + cfa->base = CFI_SP; | ||
10568 | + break; | ||
10569 | + case ORC_REG_BP: | ||
10570 | + cfa->base = CFI_BP; | ||
10571 | + break; | ||
10572 | + case ORC_REG_SP_INDIRECT: | ||
10573 | + cfa->base = CFI_SP_INDIRECT; | ||
10574 | + break; | ||
10575 | + case ORC_REG_R10: | ||
10576 | + cfa->base = CFI_R10; | ||
10577 | + break; | ||
10578 | + case ORC_REG_R13: | ||
10579 | + cfa->base = CFI_R13; | ||
10580 | + break; | ||
10581 | + case ORC_REG_DI: | ||
10582 | + cfa->base = CFI_DI; | ||
10583 | + break; | ||
10584 | + case ORC_REG_DX: | ||
10585 | + cfa->base = CFI_DX; | ||
10586 | + break; | ||
10587 | + default: | ||
10588 | + WARN_FUNC("unsupported unwind_hint sp base reg %d", | ||
10589 | + insn->sec, insn->offset, hint->sp_reg); | ||
10590 | + return -1; | ||
10591 | + } | ||
10592 | + | ||
10593 | + cfa->offset = hint->sp_offset; | ||
10594 | + insn->state.type = hint->type; | ||
10595 | + } | ||
10596 | + | ||
10597 | + return 0; | ||
10598 | +} | ||
10599 | + | ||
10600 | +static int read_retpoline_hints(struct objtool_file *file) | ||
10601 | +{ | ||
10602 | + struct section *sec; | ||
10603 | + struct instruction *insn; | ||
10604 | + struct rela *rela; | ||
10605 | + | ||
10606 | + sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); | ||
10607 | + if (!sec) | ||
10608 | + return 0; | ||
10609 | + | ||
10610 | + list_for_each_entry(rela, &sec->rela_list, list) { | ||
10611 | + if (rela->sym->type != STT_SECTION) { | ||
10612 | + WARN("unexpected relocation symbol type in %s", sec->name); | ||
10613 | + return -1; | ||
10614 | + } | ||
10615 | + | ||
10616 | + insn = find_insn(file, rela->sym->sec, rela->addend); | ||
10617 | + if (!insn) { | ||
10618 | + WARN("bad .discard.retpoline_safe entry"); | ||
10619 | + return -1; | ||
10620 | + } | ||
10621 | + | ||
10622 | + if (insn->type != INSN_JUMP_DYNAMIC && | ||
10623 | + insn->type != INSN_CALL_DYNAMIC) { | ||
10624 | + WARN_FUNC("retpoline_safe hint not an indirect jump/call", | ||
10625 | + insn->sec, insn->offset); | ||
10626 | + return -1; | ||
10627 | + } | ||
10628 | + | ||
10629 | + insn->retpoline_safe = true; | ||
10630 | + } | ||
10631 | + | ||
10632 | + return 0; | ||
10633 | +} | ||
10634 | + | ||
10635 | +static int decode_sections(struct objtool_file *file) | ||
10636 | +{ | ||
10637 | + int ret; | ||
10638 | + | ||
10639 | + ret = decode_instructions(file); | ||
10640 | + if (ret) | ||
10641 | + return ret; | ||
10642 | + | ||
10643 | + ret = add_dead_ends(file); | ||
10644 | + if (ret) | ||
10645 | + return ret; | ||
10646 | + | ||
10647 | + add_ignores(file); | ||
10648 | + | ||
10649 | + ret = add_nospec_ignores(file); | ||
10650 | + if (ret) | ||
10651 | + return ret; | ||
10652 | + | ||
10653 | + ret = add_jump_destinations(file); | ||
10654 | + if (ret) | ||
10655 | + return ret; | ||
10656 | + | ||
10657 | + ret = add_special_section_alts(file); | ||
10658 | + if (ret) | ||
10659 | + return ret; | ||
10660 | + | ||
10661 | + ret = add_call_destinations(file); | ||
10662 | + if (ret) | ||
10663 | + return ret; | ||
10664 | + | ||
10665 | + ret = add_switch_table_alts(file); | ||
10666 | + if (ret) | ||
10667 | + return ret; | ||
10668 | + | ||
10669 | + ret = read_unwind_hints(file); | ||
10670 | + if (ret) | ||
10671 | + return ret; | ||
10672 | + | ||
10673 | + ret = read_retpoline_hints(file); | ||
10674 | + if (ret) | ||
10675 | + return ret; | ||
10676 | + | ||
10677 | + return 0; | ||
10678 | +} | ||
10679 | + | ||
10680 | +static bool is_fentry_call(struct instruction *insn) | ||
10681 | +{ | ||
10682 | + if (insn->type == INSN_CALL && | ||
10683 | + insn->call_dest->type == STT_NOTYPE && | ||
10684 | + !strcmp(insn->call_dest->name, "__fentry__")) | ||
10685 | + return true; | ||
10686 | + | ||
10687 | + return false; | ||
10688 | +} | ||
10689 | + | ||
10690 | +static bool has_modified_stack_frame(struct insn_state *state) | ||
10691 | +{ | ||
10692 | + int i; | ||
10693 | + | ||
10694 | + if (state->cfa.base != initial_func_cfi.cfa.base || | ||
10695 | + state->cfa.offset != initial_func_cfi.cfa.offset || | ||
10696 | + state->stack_size != initial_func_cfi.cfa.offset || | ||
10697 | + state->drap) | ||
10698 | + return true; | ||
10699 | + | ||
10700 | + for (i = 0; i < CFI_NUM_REGS; i++) | ||
10701 | + if (state->regs[i].base != initial_func_cfi.regs[i].base || | ||
10702 | + state->regs[i].offset != initial_func_cfi.regs[i].offset) | ||
10703 | + return true; | ||
10704 | + | ||
10705 | + return false; | ||
10706 | +} | ||
10707 | + | ||
10708 | +static bool has_valid_stack_frame(struct insn_state *state) | ||
10709 | +{ | ||
10710 | + if (state->cfa.base == CFI_BP && state->regs[CFI_BP].base == CFI_CFA && | ||
10711 | + state->regs[CFI_BP].offset == -16) | ||
10712 | + return true; | ||
10713 | + | ||
10714 | + if (state->drap && state->regs[CFI_BP].base == CFI_BP) | ||
10715 | + return true; | ||
10716 | + | ||
10717 | + return false; | ||
10718 | +} | ||
10719 | + | ||
10720 | +static int update_insn_state_regs(struct instruction *insn, struct insn_state *state) | ||
10721 | +{ | ||
10722 | + struct cfi_reg *cfa = &state->cfa; | ||
10723 | + struct stack_op *op = &insn->stack_op; | ||
10724 | + | ||
10725 | + if (cfa->base != CFI_SP) | ||
10726 | + return 0; | ||
10727 | + | ||
10728 | + /* push */ | ||
10729 | + if (op->dest.type == OP_DEST_PUSH) | ||
10730 | + cfa->offset += 8; | ||
10731 | + | ||
10732 | + /* pop */ | ||
10733 | + if (op->src.type == OP_SRC_POP) | ||
10734 | + cfa->offset -= 8; | ||
10735 | + | ||
10736 | + /* add immediate to sp */ | ||
10737 | + if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD && | ||
10738 | + op->dest.reg == CFI_SP && op->src.reg == CFI_SP) | ||
10739 | + cfa->offset -= op->src.offset; | ||
10740 | + | ||
10741 | + return 0; | ||
10742 | +} | ||
10743 | + | ||
10744 | +static void save_reg(struct insn_state *state, unsigned char reg, int base, | ||
10745 | + int offset) | ||
10746 | +{ | ||
10747 | + if (arch_callee_saved_reg(reg) && | ||
10748 | + state->regs[reg].base == CFI_UNDEFINED) { | ||
10749 | + state->regs[reg].base = base; | ||
10750 | + state->regs[reg].offset = offset; | ||
10751 | + } | ||
10752 | +} | ||
10753 | + | ||
10754 | +static void restore_reg(struct insn_state *state, unsigned char reg) | ||
10755 | +{ | ||
10756 | + state->regs[reg].base = CFI_UNDEFINED; | ||
10757 | + state->regs[reg].offset = 0; | ||
10758 | +} | ||
10759 | + | ||
10760 | +/* | ||
10761 | + * A note about DRAP stack alignment: | ||
10762 | + * | ||
10763 | + * GCC has the concept of a DRAP register, which is used to help keep track of | ||
10764 | + * the stack pointer when aligning the stack. r10 or r13 is used as the DRAP | ||
10765 | + * register. The typical DRAP pattern is: | ||
10766 | + * | ||
10767 | + * 4c 8d 54 24 08 lea 0x8(%rsp),%r10 | ||
10768 | + * 48 83 e4 c0 and $0xffffffffffffffc0,%rsp | ||
10769 | + * 41 ff 72 f8 pushq -0x8(%r10) | ||
10770 | + * 55 push %rbp | ||
10771 | + * 48 89 e5 mov %rsp,%rbp | ||
10772 | + * (more pushes) | ||
10773 | + * 41 52 push %r10 | ||
10774 | + * ... | ||
10775 | + * 41 5a pop %r10 | ||
10776 | + * (more pops) | ||
10777 | + * 5d pop %rbp | ||
10778 | + * 49 8d 62 f8 lea -0x8(%r10),%rsp | ||
10779 | + * c3 retq | ||
10780 | + * | ||
10781 | + * There are some variations in the epilogues, like: | ||
10782 | + * | ||
10783 | + * 5b pop %rbx | ||
10784 | + * 41 5a pop %r10 | ||
10785 | + * 41 5c pop %r12 | ||
10786 | + * 41 5d pop %r13 | ||
10787 | + * 41 5e pop %r14 | ||
10788 | + * c9 leaveq | ||
10789 | + * 49 8d 62 f8 lea -0x8(%r10),%rsp | ||
10790 | + * c3 retq | ||
10791 | + * | ||
10792 | + * and: | ||
10793 | + * | ||
10794 | + * 4c 8b 55 e8 mov -0x18(%rbp),%r10 | ||
10795 | + * 48 8b 5d e0 mov -0x20(%rbp),%rbx | ||
10796 | + * 4c 8b 65 f0 mov -0x10(%rbp),%r12 | ||
10797 | + * 4c 8b 6d f8 mov -0x8(%rbp),%r13 | ||
10798 | + * c9 leaveq | ||
10799 | + * 49 8d 62 f8 lea -0x8(%r10),%rsp | ||
10800 | + * c3 retq | ||
10801 | + * | ||
10802 | + * Sometimes r13 is used as the DRAP register, in which case it's saved and | ||
10803 | + * restored beforehand: | ||
10804 | + * | ||
10805 | + * 41 55 push %r13 | ||
10806 | + * 4c 8d 6c 24 10 lea 0x10(%rsp),%r13 | ||
10807 | + * 48 83 e4 f0 and $0xfffffffffffffff0,%rsp | ||
10808 | + * ... | ||
10809 | + * 49 8d 65 f0 lea -0x10(%r13),%rsp | ||
10810 | + * 41 5d pop %r13 | ||
10811 | + * c3 retq | ||
10812 | + */ | ||
10813 | +static int update_insn_state(struct instruction *insn, struct insn_state *state) | ||
10814 | +{ | ||
10815 | + struct stack_op *op = &insn->stack_op; | ||
10816 | + struct cfi_reg *cfa = &state->cfa; | ||
10817 | + struct cfi_reg *regs = state->regs; | ||
10818 | + | ||
10819 | + /* stack operations don't make sense with an undefined CFA */ | ||
10820 | + if (cfa->base == CFI_UNDEFINED) { | ||
10821 | + if (insn->func) { | ||
10822 | + WARN_FUNC("undefined stack state", insn->sec, insn->offset); | ||
10823 | + return -1; | ||
10824 | + } | ||
10825 | + return 0; | ||
10826 | + } | ||
10827 | + | ||
10828 | + if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET) | ||
10829 | + return update_insn_state_regs(insn, state); | ||
10830 | + | ||
10831 | + switch (op->dest.type) { | ||
10832 | + | ||
10833 | + case OP_DEST_REG: | ||
10834 | + switch (op->src.type) { | ||
10835 | + | ||
10836 | + case OP_SRC_REG: | ||
10837 | + if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP && | ||
10838 | + cfa->base == CFI_SP && | ||
10839 | + regs[CFI_BP].base == CFI_CFA && | ||
10840 | + regs[CFI_BP].offset == -cfa->offset) { | ||
10841 | + | ||
10842 | + /* mov %rsp, %rbp */ | ||
10843 | + cfa->base = op->dest.reg; | ||
10844 | + state->bp_scratch = false; | ||
10845 | + } | ||
10846 | + | ||
10847 | + else if (op->src.reg == CFI_SP && | ||
10848 | + op->dest.reg == CFI_BP && state->drap) { | ||
10849 | + | ||
10850 | + /* drap: mov %rsp, %rbp */ | ||
10851 | + regs[CFI_BP].base = CFI_BP; | ||
10852 | + regs[CFI_BP].offset = -state->stack_size; | ||
10853 | + state->bp_scratch = false; | ||
10854 | + } | ||
10855 | + | ||
10856 | + else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { | ||
10857 | + | ||
10858 | + /* | ||
10859 | + * mov %rsp, %reg | ||
10860 | + * | ||
10861 | + * This is needed for the rare case where GCC | ||
10862 | + * does: | ||
10863 | + * | ||
10864 | + * mov %rsp, %rax | ||
10865 | + * ... | ||
10866 | + * mov %rax, %rsp | ||
10867 | + */ | ||
10868 | + state->vals[op->dest.reg].base = CFI_CFA; | ||
10869 | + state->vals[op->dest.reg].offset = -state->stack_size; | ||
10870 | + } | ||
10871 | + | ||
10872 | + else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP && | ||
10873 | + cfa->base == CFI_BP) { | ||
10874 | + | ||
10875 | + /* | ||
10876 | + * mov %rbp, %rsp | ||
10877 | + * | ||
10878 | + * Restore the original stack pointer (Clang). | ||
10879 | + */ | ||
10880 | + state->stack_size = -state->regs[CFI_BP].offset; | ||
10881 | + } | ||
10882 | + | ||
10883 | + else if (op->dest.reg == cfa->base) { | ||
10884 | + | ||
10885 | + /* mov %reg, %rsp */ | ||
10886 | + if (cfa->base == CFI_SP && | ||
10887 | + state->vals[op->src.reg].base == CFI_CFA) { | ||
10888 | + | ||
10889 | + /* | ||
10890 | + * This is needed for the rare case | ||
10891 | + * where GCC does something dumb like: | ||
10892 | + * | ||
10893 | + * lea 0x8(%rsp), %rcx | ||
10894 | + * ... | ||
10895 | + * mov %rcx, %rsp | ||
10896 | + */ | ||
10897 | + cfa->offset = -state->vals[op->src.reg].offset; | ||
10898 | + state->stack_size = cfa->offset; | ||
10899 | + | ||
10900 | + } else { | ||
10901 | + cfa->base = CFI_UNDEFINED; | ||
10902 | + cfa->offset = 0; | ||
10903 | + } | ||
10904 | + } | ||
10905 | + | ||
10906 | + break; | ||
10907 | + | ||
10908 | + case OP_SRC_ADD: | ||
10909 | + if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) { | ||
10910 | + | ||
10911 | + /* add imm, %rsp */ | ||
10912 | + state->stack_size -= op->src.offset; | ||
10913 | + if (cfa->base == CFI_SP) | ||
10914 | + cfa->offset -= op->src.offset; | ||
10915 | + break; | ||
10916 | + } | ||
10917 | + | ||
10918 | + if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { | ||
10919 | + | ||
10920 | + /* lea disp(%rbp), %rsp */ | ||
10921 | + state->stack_size = -(op->src.offset + regs[CFI_BP].offset); | ||
10922 | + break; | ||
10923 | + } | ||
10924 | + | ||
10925 | + if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { | ||
10926 | + | ||
10927 | + /* drap: lea disp(%rsp), %drap */ | ||
10928 | + state->drap_reg = op->dest.reg; | ||
10929 | + | ||
10930 | + /* | ||
10931 | + * lea disp(%rsp), %reg | ||
10932 | + * | ||
10933 | + * This is needed for the rare case where GCC | ||
10934 | + * does something dumb like: | ||
10935 | + * | ||
10936 | + * lea 0x8(%rsp), %rcx | ||
10937 | + * ... | ||
10938 | + * mov %rcx, %rsp | ||
10939 | + */ | ||
10940 | + state->vals[op->dest.reg].base = CFI_CFA; | ||
10941 | + state->vals[op->dest.reg].offset = \ | ||
10942 | + -state->stack_size + op->src.offset; | ||
10943 | + | ||
10944 | + break; | ||
10945 | + } | ||
10946 | + | ||
10947 | + if (state->drap && op->dest.reg == CFI_SP && | ||
10948 | + op->src.reg == state->drap_reg) { | ||
10949 | + | ||
10950 | + /* drap: lea disp(%drap), %rsp */ | ||
10951 | + cfa->base = CFI_SP; | ||
10952 | + cfa->offset = state->stack_size = -op->src.offset; | ||
10953 | + state->drap_reg = CFI_UNDEFINED; | ||
10954 | + state->drap = false; | ||
10955 | + break; | ||
10956 | + } | ||
10957 | + | ||
10958 | + if (op->dest.reg == state->cfa.base) { | ||
10959 | + WARN_FUNC("unsupported stack register modification", | ||
10960 | + insn->sec, insn->offset); | ||
10961 | + return -1; | ||
10962 | + } | ||
10963 | + | ||
10964 | + break; | ||
10965 | + | ||
10966 | + case OP_SRC_AND: | ||
10967 | + if (op->dest.reg != CFI_SP || | ||
10968 | + (state->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || | ||
10969 | + (state->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { | ||
10970 | + WARN_FUNC("unsupported stack pointer realignment", | ||
10971 | + insn->sec, insn->offset); | ||
10972 | + return -1; | ||
10973 | + } | ||
10974 | + | ||
10975 | + if (state->drap_reg != CFI_UNDEFINED) { | ||
10976 | + /* drap: and imm, %rsp */ | ||
10977 | + cfa->base = state->drap_reg; | ||
10978 | + cfa->offset = state->stack_size = 0; | ||
10979 | + state->drap = true; | ||
10980 | + } | ||
10981 | + | ||
10982 | + /* | ||
10983 | + * Older versions of GCC (4.8ish) realign the stack | ||
10984 | + * without DRAP, with a frame pointer. | ||
10985 | + */ | ||
10986 | + | ||
10987 | + break; | ||
10988 | + | ||
10989 | + case OP_SRC_POP: | ||
10990 | + if (!state->drap && op->dest.type == OP_DEST_REG && | ||
10991 | + op->dest.reg == cfa->base) { | ||
10992 | + | ||
10993 | + /* pop %rbp */ | ||
10994 | + cfa->base = CFI_SP; | ||
10995 | + } | ||
10996 | + | ||
10997 | + if (state->drap && cfa->base == CFI_BP_INDIRECT && | ||
10998 | + op->dest.type == OP_DEST_REG && | ||
10999 | + op->dest.reg == state->drap_reg && | ||
11000 | + state->drap_offset == -state->stack_size) { | ||
11001 | + | ||
11002 | + /* drap: pop %drap */ | ||
11003 | + cfa->base = state->drap_reg; | ||
11004 | + cfa->offset = 0; | ||
11005 | + state->drap_offset = -1; | ||
11006 | + | ||
11007 | + } else if (regs[op->dest.reg].offset == -state->stack_size) { | ||
11008 | + | ||
11009 | + /* pop %reg */ | ||
11010 | + restore_reg(state, op->dest.reg); | ||
11011 | + } | ||
11012 | + | ||
11013 | + state->stack_size -= 8; | ||
11014 | + if (cfa->base == CFI_SP) | ||
11015 | + cfa->offset -= 8; | ||
11016 | + | ||
11017 | + break; | ||
11018 | + | ||
11019 | + case OP_SRC_REG_INDIRECT: | ||
11020 | + if (state->drap && op->src.reg == CFI_BP && | ||
11021 | + op->src.offset == state->drap_offset) { | ||
11022 | + | ||
11023 | + /* drap: mov disp(%rbp), %drap */ | ||
11024 | + cfa->base = state->drap_reg; | ||
11025 | + cfa->offset = 0; | ||
11026 | + state->drap_offset = -1; | ||
11027 | + } | ||
11028 | + | ||
11029 | + if (state->drap && op->src.reg == CFI_BP && | ||
11030 | + op->src.offset == regs[op->dest.reg].offset) { | ||
11031 | + | ||
11032 | + /* drap: mov disp(%rbp), %reg */ | ||
11033 | + restore_reg(state, op->dest.reg); | ||
11034 | + | ||
11035 | + } else if (op->src.reg == cfa->base && | ||
11036 | + op->src.offset == regs[op->dest.reg].offset + cfa->offset) { | ||
11037 | + | ||
11038 | + /* mov disp(%rbp), %reg */ | ||
11039 | + /* mov disp(%rsp), %reg */ | ||
11040 | + restore_reg(state, op->dest.reg); | ||
11041 | + } | ||
11042 | + | ||
11043 | + break; | ||
11044 | + | ||
11045 | + default: | ||
11046 | + WARN_FUNC("unknown stack-related instruction", | ||
11047 | + insn->sec, insn->offset); | ||
11048 | + return -1; | ||
11049 | + } | ||
11050 | + | ||
11051 | + break; | ||
11052 | + | ||
11053 | + case OP_DEST_PUSH: | ||
11054 | + state->stack_size += 8; | ||
11055 | + if (cfa->base == CFI_SP) | ||
11056 | + cfa->offset += 8; | ||
11057 | + | ||
11058 | + if (op->src.type != OP_SRC_REG) | ||
11059 | + break; | ||
11060 | + | ||
11061 | + if (state->drap) { | ||
11062 | + if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { | ||
11063 | + | ||
11064 | + /* drap: push %drap */ | ||
11065 | + cfa->base = CFI_BP_INDIRECT; | ||
11066 | + cfa->offset = -state->stack_size; | ||
11067 | + | ||
11068 | + /* save drap so we know when to restore it */ | ||
11069 | + state->drap_offset = -state->stack_size; | ||
11070 | + | ||
11071 | + } else if (op->src.reg == CFI_BP && cfa->base == state->drap_reg) { | ||
11072 | + | ||
11073 | + /* drap: push %rbp */ | ||
11074 | + state->stack_size = 0; | ||
11075 | + | ||
11076 | + } else if (regs[op->src.reg].base == CFI_UNDEFINED) { | ||
11077 | + | ||
11078 | + /* drap: push %reg */ | ||
11079 | + save_reg(state, op->src.reg, CFI_BP, -state->stack_size); | ||
11080 | + } | ||
11081 | + | ||
11082 | + } else { | ||
11083 | + | ||
11084 | + /* push %reg */ | ||
11085 | + save_reg(state, op->src.reg, CFI_CFA, -state->stack_size); | ||
11086 | + } | ||
11087 | + | ||
11088 | + /* detect when asm code uses rbp as a scratch register */ | ||
11089 | + if (!no_fp && insn->func && op->src.reg == CFI_BP && | ||
11090 | + cfa->base != CFI_BP) | ||
11091 | + state->bp_scratch = true; | ||
11092 | + break; | ||
11093 | + | ||
11094 | + case OP_DEST_REG_INDIRECT: | ||
11095 | + | ||
11096 | + if (state->drap) { | ||
11097 | + if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { | ||
11098 | + | ||
11099 | + /* drap: mov %drap, disp(%rbp) */ | ||
11100 | + cfa->base = CFI_BP_INDIRECT; | ||
11101 | + cfa->offset = op->dest.offset; | ||
11102 | + | ||
11103 | + /* save drap offset so we know when to restore it */ | ||
11104 | + state->drap_offset = op->dest.offset; | ||
11105 | + } | ||
11106 | + | ||
11107 | + else if (regs[op->src.reg].base == CFI_UNDEFINED) { | ||
11108 | + | ||
11109 | + /* drap: mov reg, disp(%rbp) */ | ||
11110 | + save_reg(state, op->src.reg, CFI_BP, op->dest.offset); | ||
11111 | + } | ||
11112 | + | ||
11113 | + } else if (op->dest.reg == cfa->base) { | ||
11114 | + | ||
11115 | + /* mov reg, disp(%rbp) */ | ||
11116 | + /* mov reg, disp(%rsp) */ | ||
11117 | + save_reg(state, op->src.reg, CFI_CFA, | ||
11118 | + op->dest.offset - state->cfa.offset); | ||
11119 | + } | ||
11120 | + | ||
11121 | + break; | ||
11122 | + | ||
11123 | + case OP_DEST_LEAVE: | ||
11124 | + if ((!state->drap && cfa->base != CFI_BP) || | ||
11125 | + (state->drap && cfa->base != state->drap_reg)) { | ||
11126 | + WARN_FUNC("leave instruction with modified stack frame", | ||
11127 | + insn->sec, insn->offset); | ||
11128 | + return -1; | ||
11129 | + } | ||
11130 | + | ||
11131 | + /* leave (mov %rbp, %rsp; pop %rbp) */ | ||
11132 | + | ||
11133 | + state->stack_size = -state->regs[CFI_BP].offset - 8; | ||
11134 | + restore_reg(state, CFI_BP); | ||
11135 | + | ||
11136 | + if (!state->drap) { | ||
11137 | + cfa->base = CFI_SP; | ||
11138 | + cfa->offset -= 8; | ||
11139 | + } | ||
11140 | + | ||
11141 | + break; | ||
11142 | + | ||
11143 | + case OP_DEST_MEM: | ||
11144 | + if (op->src.type != OP_SRC_POP) { | ||
11145 | + WARN_FUNC("unknown stack-related memory operation", | ||
11146 | + insn->sec, insn->offset); | ||
11147 | + return -1; | ||
11148 | + } | ||
11149 | + | ||
11150 | + /* pop mem */ | ||
11151 | + state->stack_size -= 8; | ||
11152 | + if (cfa->base == CFI_SP) | ||
11153 | + cfa->offset -= 8; | ||
11154 | + | ||
11155 | + break; | ||
11156 | + | ||
11157 | + default: | ||
11158 | + WARN_FUNC("unknown stack-related instruction", | ||
11159 | + insn->sec, insn->offset); | ||
11160 | + return -1; | ||
11161 | + } | ||
11162 | + | ||
11163 | + return 0; | ||
11164 | +} | ||
11165 | + | ||
11166 | +static bool insn_state_match(struct instruction *insn, struct insn_state *state) | ||
11167 | +{ | ||
11168 | + struct insn_state *state1 = &insn->state, *state2 = state; | ||
11169 | + int i; | ||
11170 | + | ||
11171 | + if (memcmp(&state1->cfa, &state2->cfa, sizeof(state1->cfa))) { | ||
11172 | + WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d", | ||
11173 | + insn->sec, insn->offset, | ||
11174 | + state1->cfa.base, state1->cfa.offset, | ||
11175 | + state2->cfa.base, state2->cfa.offset); | ||
11176 | + | ||
11177 | + } else if (memcmp(&state1->regs, &state2->regs, sizeof(state1->regs))) { | ||
11178 | + for (i = 0; i < CFI_NUM_REGS; i++) { | ||
11179 | + if (!memcmp(&state1->regs[i], &state2->regs[i], | ||
11180 | + sizeof(struct cfi_reg))) | ||
11181 | + continue; | ||
11182 | + | ||
11183 | + WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", | ||
11184 | + insn->sec, insn->offset, | ||
11185 | + i, state1->regs[i].base, state1->regs[i].offset, | ||
11186 | + i, state2->regs[i].base, state2->regs[i].offset); | ||
11187 | + break; | ||
11188 | + } | ||
11189 | + | ||
11190 | + } else if (state1->type != state2->type) { | ||
11191 | + WARN_FUNC("stack state mismatch: type1=%d type2=%d", | ||
11192 | + insn->sec, insn->offset, state1->type, state2->type); | ||
11193 | + | ||
11194 | + } else if (state1->drap != state2->drap || | ||
11195 | + (state1->drap && state1->drap_reg != state2->drap_reg) || | ||
11196 | + (state1->drap && state1->drap_offset != state2->drap_offset)) { | ||
11197 | + WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", | ||
11198 | + insn->sec, insn->offset, | ||
11199 | + state1->drap, state1->drap_reg, state1->drap_offset, | ||
11200 | + state2->drap, state2->drap_reg, state2->drap_offset); | ||
11201 | + | ||
11202 | + } else | ||
11203 | + return true; | ||
11204 | + | ||
11205 | + return false; | ||
11206 | +} | ||
11207 | + | ||
11208 | +/* | ||
11209 | + * Follow the branch starting at the given instruction, and recursively follow | ||
11210 | + * any other branches (jumps). Meanwhile, track the frame pointer state at | ||
11211 | + * each instruction and validate all the rules described in | ||
11212 | + * tools/objtool/Documentation/stack-validation.txt. | ||
11213 | + */ | ||
11214 | +static int validate_branch(struct objtool_file *file, struct instruction *first, | ||
11215 | + struct insn_state state) | ||
11216 | +{ | ||
11217 | + struct alternative *alt; | ||
11218 | + struct instruction *insn, *next_insn; | ||
11219 | + struct section *sec; | ||
11220 | + struct symbol *func = NULL; | ||
11221 | + int ret; | ||
11222 | + | ||
11223 | + insn = first; | ||
11224 | + sec = insn->sec; | ||
11225 | + | ||
11226 | + if (insn->alt_group && list_empty(&insn->alts)) { | ||
11227 | + WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", | ||
11228 | + sec, insn->offset); | ||
11229 | + return 1; | ||
11230 | + } | ||
11231 | + | ||
11232 | + while (1) { | ||
11233 | + next_insn = next_insn_same_sec(file, insn); | ||
11234 | + | ||
11235 | + if (file->c_file && func && insn->func && func != insn->func->pfunc) { | ||
11236 | + WARN("%s() falls through to next function %s()", | ||
11237 | + func->name, insn->func->name); | ||
11238 | + return 1; | ||
11239 | + } | ||
11240 | + | ||
11241 | + func = insn->func ? insn->func->pfunc : NULL; | ||
11242 | + | ||
11243 | + if (func && insn->ignore) { | ||
11244 | + WARN_FUNC("BUG: why am I validating an ignored function?", | ||
11245 | + sec, insn->offset); | ||
11246 | + return 1; | ||
11247 | + } | ||
11248 | + | ||
11249 | + if (insn->visited) { | ||
11250 | + if (!insn->hint && !insn_state_match(insn, &state)) | ||
11251 | + return 1; | ||
11252 | + | ||
11253 | + return 0; | ||
11254 | + } | ||
11255 | + | ||
11256 | + if (insn->hint) { | ||
11257 | + if (insn->restore) { | ||
11258 | + struct instruction *save_insn, *i; | ||
11259 | + | ||
11260 | + i = insn; | ||
11261 | + save_insn = NULL; | ||
11262 | + func_for_each_insn_continue_reverse(file, insn->func, i) { | ||
11263 | + if (i->save) { | ||
11264 | + save_insn = i; | ||
11265 | + break; | ||
11266 | + } | ||
11267 | + } | ||
11268 | + | ||
11269 | + if (!save_insn) { | ||
11270 | + WARN_FUNC("no corresponding CFI save for CFI restore", | ||
11271 | + sec, insn->offset); | ||
11272 | + return 1; | ||
11273 | + } | ||
11274 | + | ||
11275 | + if (!save_insn->visited) { | ||
11276 | + /* | ||
11277 | + * Oops, no state to copy yet. | ||
11278 | + * Hopefully we can reach this | ||
11279 | + * instruction from another branch | ||
11280 | + * after the save insn has been | ||
11281 | + * visited. | ||
11282 | + */ | ||
11283 | + if (insn == first) | ||
11284 | + return 0; | ||
11285 | + | ||
11286 | + WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo", | ||
11287 | + sec, insn->offset); | ||
11288 | + return 1; | ||
11289 | + } | ||
11290 | + | ||
11291 | + insn->state = save_insn->state; | ||
11292 | + } | ||
11293 | + | ||
11294 | + state = insn->state; | ||
11295 | + | ||
11296 | + } else | ||
11297 | + insn->state = state; | ||
11298 | + | ||
11299 | + insn->visited = true; | ||
11300 | + | ||
11301 | + if (!insn->ignore_alts) { | ||
11302 | + list_for_each_entry(alt, &insn->alts, list) { | ||
11303 | + ret = validate_branch(file, alt->insn, state); | ||
11304 | + if (ret) | ||
11305 | + return 1; | ||
11306 | + } | ||
11307 | + } | ||
11308 | + | ||
11309 | + switch (insn->type) { | ||
11310 | + | ||
11311 | + case INSN_RETURN: | ||
11312 | + if (func && has_modified_stack_frame(&state)) { | ||
11313 | + WARN_FUNC("return with modified stack frame", | ||
11314 | + sec, insn->offset); | ||
11315 | + return 1; | ||
11316 | + } | ||
11317 | + | ||
11318 | + if (state.bp_scratch) { | ||
11319 | + WARN("%s uses BP as a scratch register", | ||
11320 | + insn->func->name); | ||
11321 | + return 1; | ||
11322 | + } | ||
11323 | + | ||
11324 | + return 0; | ||
11325 | + | ||
11326 | + case INSN_CALL: | ||
11327 | + if (is_fentry_call(insn)) | ||
11328 | + break; | ||
11329 | + | ||
11330 | + ret = dead_end_function(file, insn->call_dest); | ||
11331 | + if (ret == 1) | ||
11332 | + return 0; | ||
11333 | + if (ret == -1) | ||
11334 | + return 1; | ||
11335 | + | ||
11336 | + /* fallthrough */ | ||
11337 | + case INSN_CALL_DYNAMIC: | ||
11338 | + if (!no_fp && func && !has_valid_stack_frame(&state)) { | ||
11339 | + WARN_FUNC("call without frame pointer save/setup", | ||
11340 | + sec, insn->offset); | ||
11341 | + return 1; | ||
11342 | + } | ||
11343 | + break; | ||
11344 | + | ||
11345 | + case INSN_JUMP_CONDITIONAL: | ||
11346 | + case INSN_JUMP_UNCONDITIONAL: | ||
11347 | + if (insn->jump_dest && | ||
11348 | + (!func || !insn->jump_dest->func || | ||
11349 | + insn->jump_dest->func->pfunc == func)) { | ||
11350 | + ret = validate_branch(file, insn->jump_dest, | ||
11351 | + state); | ||
11352 | + if (ret) | ||
11353 | + return 1; | ||
11354 | + | ||
11355 | + } else if (func && has_modified_stack_frame(&state)) { | ||
11356 | + WARN_FUNC("sibling call from callable instruction with modified stack frame", | ||
11357 | + sec, insn->offset); | ||
11358 | + return 1; | ||
11359 | + } | ||
11360 | + | ||
11361 | + if (insn->type == INSN_JUMP_UNCONDITIONAL) | ||
11362 | + return 0; | ||
11363 | + | ||
11364 | + break; | ||
11365 | + | ||
11366 | + case INSN_JUMP_DYNAMIC: | ||
11367 | + if (func && list_empty(&insn->alts) && | ||
11368 | + has_modified_stack_frame(&state)) { | ||
11369 | + WARN_FUNC("sibling call from callable instruction with modified stack frame", | ||
11370 | + sec, insn->offset); | ||
11371 | + return 1; | ||
11372 | + } | ||
11373 | + | ||
11374 | + return 0; | ||
11375 | + | ||
11376 | + case INSN_CONTEXT_SWITCH: | ||
11377 | + if (func && (!next_insn || !next_insn->hint)) { | ||
11378 | + WARN_FUNC("unsupported instruction in callable function", | ||
11379 | + sec, insn->offset); | ||
11380 | + return 1; | ||
11381 | + } | ||
11382 | + return 0; | ||
11383 | + | ||
11384 | + case INSN_STACK: | ||
11385 | + if (update_insn_state(insn, &state)) | ||
11386 | + return 1; | ||
11387 | + | ||
11388 | + break; | ||
11389 | + | ||
11390 | + default: | ||
11391 | + break; | ||
11392 | + } | ||
11393 | + | ||
11394 | + if (insn->dead_end) | ||
11395 | + return 0; | ||
11396 | + | ||
11397 | + if (!next_insn) { | ||
11398 | + if (state.cfa.base == CFI_UNDEFINED) | ||
11399 | + return 0; | ||
11400 | + WARN("%s: unexpected end of section", sec->name); | ||
11401 | + return 1; | ||
11402 | + } | ||
11403 | + | ||
11404 | + insn = next_insn; | ||
11405 | + } | ||
11406 | + | ||
11407 | + return 0; | ||
11408 | +} | ||
11409 | + | ||
11410 | +static int validate_unwind_hints(struct objtool_file *file) | ||
11411 | +{ | ||
11412 | + struct instruction *insn; | ||
11413 | + int ret, warnings = 0; | ||
11414 | + struct insn_state state; | ||
11415 | + | ||
11416 | + if (!file->hints) | ||
11417 | + return 0; | ||
11418 | + | ||
11419 | + clear_insn_state(&state); | ||
11420 | + | ||
11421 | + for_each_insn(file, insn) { | ||
11422 | + if (insn->hint && !insn->visited) { | ||
11423 | + ret = validate_branch(file, insn, state); | ||
11424 | + warnings += ret; | ||
11425 | + } | ||
11426 | + } | ||
11427 | + | ||
11428 | + return warnings; | ||
11429 | +} | ||
11430 | + | ||
11431 | +static int validate_retpoline(struct objtool_file *file) | ||
11432 | +{ | ||
11433 | + struct instruction *insn; | ||
11434 | + int warnings = 0; | ||
11435 | + | ||
11436 | + for_each_insn(file, insn) { | ||
11437 | + if (insn->type != INSN_JUMP_DYNAMIC && | ||
11438 | + insn->type != INSN_CALL_DYNAMIC) | ||
11439 | + continue; | ||
11440 | + | ||
11441 | + if (insn->retpoline_safe) | ||
11442 | + continue; | ||
11443 | + | ||
11444 | + /* | ||
11445 | + * .init.text code is ran before userspace and thus doesn't | ||
11446 | + * strictly need retpolines, except for modules which are | ||
11447 | + * loaded late, they very much do need retpoline in their | ||
11448 | + * .init.text | ||
11449 | + */ | ||
11450 | + if (!strcmp(insn->sec->name, ".init.text") && !module) | ||
11451 | + continue; | ||
11452 | + | ||
11453 | + WARN_FUNC("indirect %s found in RETPOLINE build", | ||
11454 | + insn->sec, insn->offset, | ||
11455 | + insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); | ||
11456 | + | ||
11457 | + warnings++; | ||
11458 | + } | ||
11459 | + | ||
11460 | + return warnings; | ||
11461 | +} | ||
11462 | + | ||
11463 | +static bool is_kasan_insn(struct instruction *insn) | ||
11464 | +{ | ||
11465 | + return (insn->type == INSN_CALL && | ||
11466 | + !strcmp(insn->call_dest->name, "__asan_handle_no_return")); | ||
11467 | +} | ||
11468 | + | ||
11469 | +static bool is_ubsan_insn(struct instruction *insn) | ||
11470 | +{ | ||
11471 | + return (insn->type == INSN_CALL && | ||
11472 | + !strcmp(insn->call_dest->name, | ||
11473 | + "__ubsan_handle_builtin_unreachable")); | ||
11474 | +} | ||
11475 | + | ||
11476 | +static bool ignore_unreachable_insn(struct instruction *insn) | ||
11477 | +{ | ||
11478 | + int i; | ||
11479 | + | ||
11480 | + if (insn->ignore || insn->type == INSN_NOP) | ||
11481 | + return true; | ||
11482 | + | ||
11483 | + /* | ||
11484 | + * Ignore any unused exceptions. This can happen when a whitelisted | ||
11485 | + * function has an exception table entry. | ||
11486 | + * | ||
11487 | + * Also ignore alternative replacement instructions. This can happen | ||
11488 | + * when a whitelisted function uses one of the ALTERNATIVE macros. | ||
11489 | + */ | ||
11490 | + if (!strcmp(insn->sec->name, ".fixup") || | ||
11491 | + !strcmp(insn->sec->name, ".altinstr_replacement") || | ||
11492 | + !strcmp(insn->sec->name, ".altinstr_aux")) | ||
11493 | + return true; | ||
11494 | + | ||
11495 | + /* | ||
11496 | + * Check if this (or a subsequent) instruction is related to | ||
11497 | + * CONFIG_UBSAN or CONFIG_KASAN. | ||
11498 | + * | ||
11499 | + * End the search at 5 instructions to avoid going into the weeds. | ||
11500 | + */ | ||
11501 | + if (!insn->func) | ||
11502 | + return false; | ||
11503 | + for (i = 0; i < 5; i++) { | ||
11504 | + | ||
11505 | + if (is_kasan_insn(insn) || is_ubsan_insn(insn)) | ||
11506 | + return true; | ||
11507 | + | ||
11508 | + if (insn->type == INSN_JUMP_UNCONDITIONAL) { | ||
11509 | + if (insn->jump_dest && | ||
11510 | + insn->jump_dest->func == insn->func) { | ||
11511 | + insn = insn->jump_dest; | ||
11512 | + continue; | ||
11513 | + } | ||
11514 | + | ||
11515 | + break; | ||
11516 | + } | ||
11517 | + | ||
11518 | + if (insn->offset + insn->len >= insn->func->offset + insn->func->len) | ||
11519 | + break; | ||
11520 | + | ||
11521 | + insn = list_next_entry(insn, list); | ||
11522 | + } | ||
11523 | + | ||
11524 | + return false; | ||
11525 | +} | ||
11526 | + | ||
11527 | +static int validate_functions(struct objtool_file *file) | ||
11528 | +{ | ||
11529 | + struct section *sec; | ||
11530 | + struct symbol *func; | ||
11531 | + struct instruction *insn; | ||
11532 | + struct insn_state state; | ||
11533 | + int ret, warnings = 0; | ||
11534 | + | ||
11535 | + clear_insn_state(&state); | ||
11536 | + | ||
11537 | + state.cfa = initial_func_cfi.cfa; | ||
11538 | + memcpy(&state.regs, &initial_func_cfi.regs, | ||
11539 | + CFI_NUM_REGS * sizeof(struct cfi_reg)); | ||
11540 | + state.stack_size = initial_func_cfi.cfa.offset; | ||
11541 | + | ||
11542 | + for_each_sec(file, sec) { | ||
11543 | + list_for_each_entry(func, &sec->symbol_list, list) { | ||
11544 | + if (func->type != STT_FUNC || func->pfunc != func) | ||
11545 | + continue; | ||
11546 | + | ||
11547 | + insn = find_insn(file, sec, func->offset); | ||
11548 | + if (!insn || insn->ignore) | ||
11549 | + continue; | ||
11550 | + | ||
11551 | + ret = validate_branch(file, insn, state); | ||
11552 | + warnings += ret; | ||
11553 | + } | ||
11554 | + } | ||
11555 | + | ||
11556 | + return warnings; | ||
11557 | +} | ||
11558 | + | ||
11559 | +static int validate_reachable_instructions(struct objtool_file *file) | ||
11560 | +{ | ||
11561 | + struct instruction *insn; | ||
11562 | + | ||
11563 | + if (file->ignore_unreachables) | ||
11564 | + return 0; | ||
11565 | + | ||
11566 | + for_each_insn(file, insn) { | ||
11567 | + if (insn->visited || ignore_unreachable_insn(insn)) | ||
11568 | + continue; | ||
11569 | + | ||
11570 | + WARN_FUNC("unreachable instruction", insn->sec, insn->offset); | ||
11571 | + return 1; | ||
11572 | + } | ||
11573 | + | ||
11574 | + return 0; | ||
11575 | +} | ||
11576 | + | ||
11577 | +static void cleanup(struct objtool_file *file) | ||
11578 | +{ | ||
11579 | + struct instruction *insn, *tmpinsn; | ||
11580 | + struct alternative *alt, *tmpalt; | ||
11581 | + | ||
11582 | + list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) { | ||
11583 | + list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { | ||
11584 | + list_del(&alt->list); | ||
11585 | + free(alt); | ||
11586 | + } | ||
11587 | + list_del(&insn->list); | ||
11588 | + hash_del(&insn->hash); | ||
11589 | + free(insn); | ||
11590 | + } | ||
11591 | + elf_close(file->elf); | ||
11592 | +} | ||
11593 | + | ||
11594 | +int check(const char *_objname, bool orc) | ||
11595 | +{ | ||
11596 | + struct objtool_file file; | ||
11597 | + int ret, warnings = 0; | ||
11598 | + | ||
11599 | + objname = _objname; | ||
11600 | + | ||
11601 | + file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); | ||
11602 | + if (!file.elf) | ||
11603 | + return 1; | ||
11604 | + | ||
11605 | + INIT_LIST_HEAD(&file.insn_list); | ||
11606 | + hash_init(file.insn_hash); | ||
11607 | + file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); | ||
11608 | + file.rodata = find_section_by_name(file.elf, ".rodata"); | ||
11609 | + file.c_file = find_section_by_name(file.elf, ".comment"); | ||
11610 | + file.ignore_unreachables = no_unreachable; | ||
11611 | + file.hints = false; | ||
11612 | + | ||
11613 | + arch_initial_func_cfi_state(&initial_func_cfi); | ||
11614 | + | ||
11615 | + ret = decode_sections(&file); | ||
11616 | + if (ret < 0) | ||
11617 | + goto out; | ||
11618 | + warnings += ret; | ||
11619 | + | ||
11620 | + if (list_empty(&file.insn_list)) | ||
11621 | + goto out; | ||
11622 | + | ||
11623 | + if (retpoline) { | ||
11624 | + ret = validate_retpoline(&file); | ||
11625 | + if (ret < 0) | ||
11626 | + return ret; | ||
11627 | + warnings += ret; | ||
11628 | + } | ||
11629 | + | ||
11630 | + ret = validate_functions(&file); | ||
11631 | + if (ret < 0) | ||
11632 | + goto out; | ||
11633 | + warnings += ret; | ||
11634 | + | ||
11635 | + ret = validate_unwind_hints(&file); | ||
11636 | + if (ret < 0) | ||
11637 | + goto out; | ||
11638 | + warnings += ret; | ||
11639 | + | ||
11640 | + if (!warnings) { | ||
11641 | + ret = validate_reachable_instructions(&file); | ||
11642 | + if (ret < 0) | ||
11643 | + goto out; | ||
11644 | + warnings += ret; | ||
11645 | + } | ||
11646 | + | ||
11647 | + if (orc) { | ||
11648 | + ret = create_orc(&file); | ||
11649 | + if (ret < 0) | ||
11650 | + goto out; | ||
11651 | + | ||
11652 | + ret = create_orc_sections(&file); | ||
11653 | + if (ret < 0) | ||
11654 | + goto out; | ||
11655 | + | ||
11656 | + ret = elf_write(file.elf); | ||
11657 | + if (ret < 0) | ||
11658 | + goto out; | ||
11659 | + } | ||
11660 | + | ||
11661 | +out: | ||
11662 | + cleanup(&file); | ||
11663 | + | ||
11664 | + /* ignore warnings for now until we get all the code cleaned up */ | ||
11665 | + if (ret || warnings) | ||
11666 | + return 0; | ||
11667 | + return 0; | ||
11668 | +} | ||
11669 | diff --git a/tools/objtool/check.h b/tools/objtool/check.h | ||
11670 | new file mode 100644 | ||
11671 | index 000000000000..c6b68fcb926f | ||
11672 | --- /dev/null | ||
11673 | +++ b/tools/objtool/check.h | ||
11674 | @@ -0,0 +1,82 @@ | ||
11675 | +/* | ||
11676 | + * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
11677 | + * | ||
11678 | + * This program is free software; you can redistribute it and/or | ||
11679 | + * modify it under the terms of the GNU General Public License | ||
11680 | + * as published by the Free Software Foundation; either version 2 | ||
11681 | + * of the License, or (at your option) any later version. | ||
11682 | + * | ||
11683 | + * This program is distributed in the hope that it will be useful, | ||
11684 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11685 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11686 | + * GNU General Public License for more details. | ||
11687 | + * | ||
11688 | + * You should have received a copy of the GNU General Public License | ||
11689 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
11690 | + */ | ||
11691 | + | ||
11692 | +#ifndef _CHECK_H | ||
11693 | +#define _CHECK_H | ||
11694 | + | ||
11695 | +#include <stdbool.h> | ||
11696 | +#include "elf.h" | ||
11697 | +#include "cfi.h" | ||
11698 | +#include "arch.h" | ||
11699 | +#include "orc.h" | ||
11700 | +#include <linux/hashtable.h> | ||
11701 | + | ||
11702 | +struct insn_state { | ||
11703 | + struct cfi_reg cfa; | ||
11704 | + struct cfi_reg regs[CFI_NUM_REGS]; | ||
11705 | + int stack_size; | ||
11706 | + unsigned char type; | ||
11707 | + bool bp_scratch; | ||
11708 | + bool drap; | ||
11709 | + int drap_reg, drap_offset; | ||
11710 | + struct cfi_reg vals[CFI_NUM_REGS]; | ||
11711 | +}; | ||
11712 | + | ||
11713 | +struct instruction { | ||
11714 | + struct list_head list; | ||
11715 | + struct hlist_node hash; | ||
11716 | + struct section *sec; | ||
11717 | + unsigned long offset; | ||
11718 | + unsigned int len; | ||
11719 | + unsigned char type; | ||
11720 | + unsigned long immediate; | ||
11721 | + bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; | ||
11722 | + bool retpoline_safe; | ||
11723 | + struct symbol *call_dest; | ||
11724 | + struct instruction *jump_dest; | ||
11725 | + struct instruction *first_jump_src; | ||
11726 | + struct list_head alts; | ||
11727 | + struct symbol *func; | ||
11728 | + struct stack_op stack_op; | ||
11729 | + struct insn_state state; | ||
11730 | + struct orc_entry orc; | ||
11731 | +}; | ||
11732 | + | ||
11733 | +struct objtool_file { | ||
11734 | + struct elf *elf; | ||
11735 | + struct list_head insn_list; | ||
11736 | + DECLARE_HASHTABLE(insn_hash, 16); | ||
11737 | + struct section *rodata, *whitelist; | ||
11738 | + bool ignore_unreachables, c_file, hints; | ||
11739 | +}; | ||
11740 | + | ||
11741 | +int check(const char *objname, bool orc); | ||
11742 | + | ||
11743 | +struct instruction *find_insn(struct objtool_file *file, | ||
11744 | + struct section *sec, unsigned long offset); | ||
11745 | + | ||
11746 | +#define for_each_insn(file, insn) \ | ||
11747 | + list_for_each_entry(insn, &file->insn_list, list) | ||
11748 | + | ||
11749 | +#define sec_for_each_insn(file, sec, insn) \ | ||
11750 | + for (insn = find_insn(file, sec, 0); \ | ||
11751 | + insn && &insn->list != &file->insn_list && \ | ||
11752 | + insn->sec == sec; \ | ||
11753 | + insn = list_next_entry(insn, list)) | ||
11754 | + | ||
11755 | + | ||
11756 | +#endif /* _CHECK_H */ | ||
11757 | diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c | ||
11758 | index faacf0c89976..4e60e105583e 100644 | ||
11759 | --- a/tools/objtool/elf.c | ||
11760 | +++ b/tools/objtool/elf.c | ||
11761 | @@ -31,13 +31,6 @@ | ||
11762 | #include "elf.h" | ||
11763 | #include "warn.h" | ||
11764 | |||
11765 | -/* | ||
11766 | - * Fallback for systems without this "read, mmaping if possible" cmd. | ||
11767 | - */ | ||
11768 | -#ifndef ELF_C_READ_MMAP | ||
11769 | -#define ELF_C_READ_MMAP ELF_C_READ | ||
11770 | -#endif | ||
11771 | - | ||
11772 | struct section *find_section_by_name(struct elf *elf, const char *name) | ||
11773 | { | ||
11774 | struct section *sec; | ||
11775 | @@ -86,6 +79,19 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) | ||
11776 | return NULL; | ||
11777 | } | ||
11778 | |||
11779 | +struct symbol *find_symbol_by_name(struct elf *elf, const char *name) | ||
11780 | +{ | ||
11781 | + struct section *sec; | ||
11782 | + struct symbol *sym; | ||
11783 | + | ||
11784 | + list_for_each_entry(sec, &elf->sections, list) | ||
11785 | + list_for_each_entry(sym, &sec->symbol_list, list) | ||
11786 | + if (!strcmp(sym->name, name)) | ||
11787 | + return sym; | ||
11788 | + | ||
11789 | + return NULL; | ||
11790 | +} | ||
11791 | + | ||
11792 | struct symbol *find_symbol_containing(struct section *sec, unsigned long offset) | ||
11793 | { | ||
11794 | struct symbol *sym; | ||
11795 | @@ -140,12 +146,12 @@ static int read_sections(struct elf *elf) | ||
11796 | int i; | ||
11797 | |||
11798 | if (elf_getshdrnum(elf->elf, §ions_nr)) { | ||
11799 | - perror("elf_getshdrnum"); | ||
11800 | + WARN_ELF("elf_getshdrnum"); | ||
11801 | return -1; | ||
11802 | } | ||
11803 | |||
11804 | if (elf_getshdrstrndx(elf->elf, &shstrndx)) { | ||
11805 | - perror("elf_getshdrstrndx"); | ||
11806 | + WARN_ELF("elf_getshdrstrndx"); | ||
11807 | return -1; | ||
11808 | } | ||
11809 | |||
11810 | @@ -166,37 +172,37 @@ static int read_sections(struct elf *elf) | ||
11811 | |||
11812 | s = elf_getscn(elf->elf, i); | ||
11813 | if (!s) { | ||
11814 | - perror("elf_getscn"); | ||
11815 | + WARN_ELF("elf_getscn"); | ||
11816 | return -1; | ||
11817 | } | ||
11818 | |||
11819 | sec->idx = elf_ndxscn(s); | ||
11820 | |||
11821 | if (!gelf_getshdr(s, &sec->sh)) { | ||
11822 | - perror("gelf_getshdr"); | ||
11823 | + WARN_ELF("gelf_getshdr"); | ||
11824 | return -1; | ||
11825 | } | ||
11826 | |||
11827 | sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); | ||
11828 | if (!sec->name) { | ||
11829 | - perror("elf_strptr"); | ||
11830 | + WARN_ELF("elf_strptr"); | ||
11831 | return -1; | ||
11832 | } | ||
11833 | |||
11834 | - sec->elf_data = elf_getdata(s, NULL); | ||
11835 | - if (!sec->elf_data) { | ||
11836 | - perror("elf_getdata"); | ||
11837 | - return -1; | ||
11838 | - } | ||
11839 | - | ||
11840 | - if (sec->elf_data->d_off != 0 || | ||
11841 | - sec->elf_data->d_size != sec->sh.sh_size) { | ||
11842 | - WARN("unexpected data attributes for %s", sec->name); | ||
11843 | - return -1; | ||
11844 | + if (sec->sh.sh_size != 0) { | ||
11845 | + sec->data = elf_getdata(s, NULL); | ||
11846 | + if (!sec->data) { | ||
11847 | + WARN_ELF("elf_getdata"); | ||
11848 | + return -1; | ||
11849 | + } | ||
11850 | + if (sec->data->d_off != 0 || | ||
11851 | + sec->data->d_size != sec->sh.sh_size) { | ||
11852 | + WARN("unexpected data attributes for %s", | ||
11853 | + sec->name); | ||
11854 | + return -1; | ||
11855 | + } | ||
11856 | } | ||
11857 | - | ||
11858 | - sec->data = (unsigned long)sec->elf_data->d_buf; | ||
11859 | - sec->len = sec->elf_data->d_size; | ||
11860 | + sec->len = sec->sh.sh_size; | ||
11861 | } | ||
11862 | |||
11863 | /* sanity check, one more call to elf_nextscn() should return NULL */ | ||
11864 | @@ -210,10 +216,11 @@ static int read_sections(struct elf *elf) | ||
11865 | |||
11866 | static int read_symbols(struct elf *elf) | ||
11867 | { | ||
11868 | - struct section *symtab; | ||
11869 | - struct symbol *sym; | ||
11870 | + struct section *symtab, *sec; | ||
11871 | + struct symbol *sym, *pfunc; | ||
11872 | struct list_head *entry, *tmp; | ||
11873 | int symbols_nr, i; | ||
11874 | + char *coldstr; | ||
11875 | |||
11876 | symtab = find_section_by_name(elf, ".symtab"); | ||
11877 | if (!symtab) { | ||
11878 | @@ -233,15 +240,15 @@ static int read_symbols(struct elf *elf) | ||
11879 | |||
11880 | sym->idx = i; | ||
11881 | |||
11882 | - if (!gelf_getsym(symtab->elf_data, i, &sym->sym)) { | ||
11883 | - perror("gelf_getsym"); | ||
11884 | + if (!gelf_getsym(symtab->data, i, &sym->sym)) { | ||
11885 | + WARN_ELF("gelf_getsym"); | ||
11886 | goto err; | ||
11887 | } | ||
11888 | |||
11889 | sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, | ||
11890 | sym->sym.st_name); | ||
11891 | if (!sym->name) { | ||
11892 | - perror("elf_strptr"); | ||
11893 | + WARN_ELF("elf_strptr"); | ||
11894 | goto err; | ||
11895 | } | ||
11896 | |||
11897 | @@ -288,6 +295,30 @@ static int read_symbols(struct elf *elf) | ||
11898 | hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx); | ||
11899 | } | ||
11900 | |||
11901 | + /* Create parent/child links for any cold subfunctions */ | ||
11902 | + list_for_each_entry(sec, &elf->sections, list) { | ||
11903 | + list_for_each_entry(sym, &sec->symbol_list, list) { | ||
11904 | + if (sym->type != STT_FUNC) | ||
11905 | + continue; | ||
11906 | + sym->pfunc = sym->cfunc = sym; | ||
11907 | + coldstr = strstr(sym->name, ".cold."); | ||
11908 | + if (coldstr) { | ||
11909 | + coldstr[0] = '\0'; | ||
11910 | + pfunc = find_symbol_by_name(elf, sym->name); | ||
11911 | + coldstr[0] = '.'; | ||
11912 | + | ||
11913 | + if (!pfunc) { | ||
11914 | + WARN("%s(): can't find parent function", | ||
11915 | + sym->name); | ||
11916 | + goto err; | ||
11917 | + } | ||
11918 | + | ||
11919 | + sym->pfunc = pfunc; | ||
11920 | + pfunc->cfunc = sym; | ||
11921 | + } | ||
11922 | + } | ||
11923 | + } | ||
11924 | + | ||
11925 | return 0; | ||
11926 | |||
11927 | err: | ||
11928 | @@ -323,8 +354,8 @@ static int read_relas(struct elf *elf) | ||
11929 | } | ||
11930 | memset(rela, 0, sizeof(*rela)); | ||
11931 | |||
11932 | - if (!gelf_getrela(sec->elf_data, i, &rela->rela)) { | ||
11933 | - perror("gelf_getrela"); | ||
11934 | + if (!gelf_getrela(sec->data, i, &rela->rela)) { | ||
11935 | + WARN_ELF("gelf_getrela"); | ||
11936 | return -1; | ||
11937 | } | ||
11938 | |||
11939 | @@ -348,9 +379,10 @@ static int read_relas(struct elf *elf) | ||
11940 | return 0; | ||
11941 | } | ||
11942 | |||
11943 | -struct elf *elf_open(const char *name) | ||
11944 | +struct elf *elf_open(const char *name, int flags) | ||
11945 | { | ||
11946 | struct elf *elf; | ||
11947 | + Elf_Cmd cmd; | ||
11948 | |||
11949 | elf_version(EV_CURRENT); | ||
11950 | |||
11951 | @@ -363,27 +395,28 @@ struct elf *elf_open(const char *name) | ||
11952 | |||
11953 | INIT_LIST_HEAD(&elf->sections); | ||
11954 | |||
11955 | - elf->name = strdup(name); | ||
11956 | - if (!elf->name) { | ||
11957 | - perror("strdup"); | ||
11958 | - goto err; | ||
11959 | - } | ||
11960 | - | ||
11961 | - elf->fd = open(name, O_RDONLY); | ||
11962 | + elf->fd = open(name, flags); | ||
11963 | if (elf->fd == -1) { | ||
11964 | fprintf(stderr, "objtool: Can't open '%s': %s\n", | ||
11965 | name, strerror(errno)); | ||
11966 | goto err; | ||
11967 | } | ||
11968 | |||
11969 | - elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); | ||
11970 | + if ((flags & O_ACCMODE) == O_RDONLY) | ||
11971 | + cmd = ELF_C_READ_MMAP; | ||
11972 | + else if ((flags & O_ACCMODE) == O_RDWR) | ||
11973 | + cmd = ELF_C_RDWR; | ||
11974 | + else /* O_WRONLY */ | ||
11975 | + cmd = ELF_C_WRITE; | ||
11976 | + | ||
11977 | + elf->elf = elf_begin(elf->fd, cmd, NULL); | ||
11978 | if (!elf->elf) { | ||
11979 | - perror("elf_begin"); | ||
11980 | + WARN_ELF("elf_begin"); | ||
11981 | goto err; | ||
11982 | } | ||
11983 | |||
11984 | if (!gelf_getehdr(elf->elf, &elf->ehdr)) { | ||
11985 | - perror("gelf_getehdr"); | ||
11986 | + WARN_ELF("gelf_getehdr"); | ||
11987 | goto err; | ||
11988 | } | ||
11989 | |||
11990 | @@ -403,12 +436,212 @@ struct elf *elf_open(const char *name) | ||
11991 | return NULL; | ||
11992 | } | ||
11993 | |||
11994 | +struct section *elf_create_section(struct elf *elf, const char *name, | ||
11995 | + size_t entsize, int nr) | ||
11996 | +{ | ||
11997 | + struct section *sec, *shstrtab; | ||
11998 | + size_t size = entsize * nr; | ||
11999 | + struct Elf_Scn *s; | ||
12000 | + Elf_Data *data; | ||
12001 | + | ||
12002 | + sec = malloc(sizeof(*sec)); | ||
12003 | + if (!sec) { | ||
12004 | + perror("malloc"); | ||
12005 | + return NULL; | ||
12006 | + } | ||
12007 | + memset(sec, 0, sizeof(*sec)); | ||
12008 | + | ||
12009 | + INIT_LIST_HEAD(&sec->symbol_list); | ||
12010 | + INIT_LIST_HEAD(&sec->rela_list); | ||
12011 | + hash_init(sec->rela_hash); | ||
12012 | + hash_init(sec->symbol_hash); | ||
12013 | + | ||
12014 | + list_add_tail(&sec->list, &elf->sections); | ||
12015 | + | ||
12016 | + s = elf_newscn(elf->elf); | ||
12017 | + if (!s) { | ||
12018 | + WARN_ELF("elf_newscn"); | ||
12019 | + return NULL; | ||
12020 | + } | ||
12021 | + | ||
12022 | + sec->name = strdup(name); | ||
12023 | + if (!sec->name) { | ||
12024 | + perror("strdup"); | ||
12025 | + return NULL; | ||
12026 | + } | ||
12027 | + | ||
12028 | + sec->idx = elf_ndxscn(s); | ||
12029 | + sec->len = size; | ||
12030 | + sec->changed = true; | ||
12031 | + | ||
12032 | + sec->data = elf_newdata(s); | ||
12033 | + if (!sec->data) { | ||
12034 | + WARN_ELF("elf_newdata"); | ||
12035 | + return NULL; | ||
12036 | + } | ||
12037 | + | ||
12038 | + sec->data->d_size = size; | ||
12039 | + sec->data->d_align = 1; | ||
12040 | + | ||
12041 | + if (size) { | ||
12042 | + sec->data->d_buf = malloc(size); | ||
12043 | + if (!sec->data->d_buf) { | ||
12044 | + perror("malloc"); | ||
12045 | + return NULL; | ||
12046 | + } | ||
12047 | + memset(sec->data->d_buf, 0, size); | ||
12048 | + } | ||
12049 | + | ||
12050 | + if (!gelf_getshdr(s, &sec->sh)) { | ||
12051 | + WARN_ELF("gelf_getshdr"); | ||
12052 | + return NULL; | ||
12053 | + } | ||
12054 | + | ||
12055 | + sec->sh.sh_size = size; | ||
12056 | + sec->sh.sh_entsize = entsize; | ||
12057 | + sec->sh.sh_type = SHT_PROGBITS; | ||
12058 | + sec->sh.sh_addralign = 1; | ||
12059 | + sec->sh.sh_flags = SHF_ALLOC; | ||
12060 | + | ||
12061 | + | ||
12062 | + /* Add section name to .shstrtab */ | ||
12063 | + shstrtab = find_section_by_name(elf, ".shstrtab"); | ||
12064 | + if (!shstrtab) { | ||
12065 | + WARN("can't find .shstrtab section"); | ||
12066 | + return NULL; | ||
12067 | + } | ||
12068 | + | ||
12069 | + s = elf_getscn(elf->elf, shstrtab->idx); | ||
12070 | + if (!s) { | ||
12071 | + WARN_ELF("elf_getscn"); | ||
12072 | + return NULL; | ||
12073 | + } | ||
12074 | + | ||
12075 | + data = elf_newdata(s); | ||
12076 | + if (!data) { | ||
12077 | + WARN_ELF("elf_newdata"); | ||
12078 | + return NULL; | ||
12079 | + } | ||
12080 | + | ||
12081 | + data->d_buf = sec->name; | ||
12082 | + data->d_size = strlen(name) + 1; | ||
12083 | + data->d_align = 1; | ||
12084 | + | ||
12085 | + sec->sh.sh_name = shstrtab->len; | ||
12086 | + | ||
12087 | + shstrtab->len += strlen(name) + 1; | ||
12088 | + shstrtab->changed = true; | ||
12089 | + | ||
12090 | + return sec; | ||
12091 | +} | ||
12092 | + | ||
12093 | +struct section *elf_create_rela_section(struct elf *elf, struct section *base) | ||
12094 | +{ | ||
12095 | + char *relaname; | ||
12096 | + struct section *sec; | ||
12097 | + | ||
12098 | + relaname = malloc(strlen(base->name) + strlen(".rela") + 1); | ||
12099 | + if (!relaname) { | ||
12100 | + perror("malloc"); | ||
12101 | + return NULL; | ||
12102 | + } | ||
12103 | + strcpy(relaname, ".rela"); | ||
12104 | + strcat(relaname, base->name); | ||
12105 | + | ||
12106 | + sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); | ||
12107 | + free(relaname); | ||
12108 | + if (!sec) | ||
12109 | + return NULL; | ||
12110 | + | ||
12111 | + base->rela = sec; | ||
12112 | + sec->base = base; | ||
12113 | + | ||
12114 | + sec->sh.sh_type = SHT_RELA; | ||
12115 | + sec->sh.sh_addralign = 8; | ||
12116 | + sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; | ||
12117 | + sec->sh.sh_info = base->idx; | ||
12118 | + sec->sh.sh_flags = SHF_INFO_LINK; | ||
12119 | + | ||
12120 | + return sec; | ||
12121 | +} | ||
12122 | + | ||
12123 | +int elf_rebuild_rela_section(struct section *sec) | ||
12124 | +{ | ||
12125 | + struct rela *rela; | ||
12126 | + int nr, idx = 0, size; | ||
12127 | + GElf_Rela *relas; | ||
12128 | + | ||
12129 | + nr = 0; | ||
12130 | + list_for_each_entry(rela, &sec->rela_list, list) | ||
12131 | + nr++; | ||
12132 | + | ||
12133 | + size = nr * sizeof(*relas); | ||
12134 | + relas = malloc(size); | ||
12135 | + if (!relas) { | ||
12136 | + perror("malloc"); | ||
12137 | + return -1; | ||
12138 | + } | ||
12139 | + | ||
12140 | + sec->data->d_buf = relas; | ||
12141 | + sec->data->d_size = size; | ||
12142 | + | ||
12143 | + sec->sh.sh_size = size; | ||
12144 | + | ||
12145 | + idx = 0; | ||
12146 | + list_for_each_entry(rela, &sec->rela_list, list) { | ||
12147 | + relas[idx].r_offset = rela->offset; | ||
12148 | + relas[idx].r_addend = rela->addend; | ||
12149 | + relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type); | ||
12150 | + idx++; | ||
12151 | + } | ||
12152 | + | ||
12153 | + return 0; | ||
12154 | +} | ||
12155 | + | ||
12156 | +int elf_write(struct elf *elf) | ||
12157 | +{ | ||
12158 | + struct section *sec; | ||
12159 | + Elf_Scn *s; | ||
12160 | + | ||
12161 | + /* Update section headers for changed sections: */ | ||
12162 | + list_for_each_entry(sec, &elf->sections, list) { | ||
12163 | + if (sec->changed) { | ||
12164 | + s = elf_getscn(elf->elf, sec->idx); | ||
12165 | + if (!s) { | ||
12166 | + WARN_ELF("elf_getscn"); | ||
12167 | + return -1; | ||
12168 | + } | ||
12169 | + if (!gelf_update_shdr(s, &sec->sh)) { | ||
12170 | + WARN_ELF("gelf_update_shdr"); | ||
12171 | + return -1; | ||
12172 | + } | ||
12173 | + } | ||
12174 | + } | ||
12175 | + | ||
12176 | + /* Make sure the new section header entries get updated properly. */ | ||
12177 | + elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY); | ||
12178 | + | ||
12179 | + /* Write all changes to the file. */ | ||
12180 | + if (elf_update(elf->elf, ELF_C_WRITE) < 0) { | ||
12181 | + WARN_ELF("elf_update"); | ||
12182 | + return -1; | ||
12183 | + } | ||
12184 | + | ||
12185 | + return 0; | ||
12186 | +} | ||
12187 | + | ||
12188 | void elf_close(struct elf *elf) | ||
12189 | { | ||
12190 | struct section *sec, *tmpsec; | ||
12191 | struct symbol *sym, *tmpsym; | ||
12192 | struct rela *rela, *tmprela; | ||
12193 | |||
12194 | + if (elf->elf) | ||
12195 | + elf_end(elf->elf); | ||
12196 | + | ||
12197 | + if (elf->fd > 0) | ||
12198 | + close(elf->fd); | ||
12199 | + | ||
12200 | list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { | ||
12201 | list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { | ||
12202 | list_del(&sym->list); | ||
12203 | @@ -423,11 +656,6 @@ void elf_close(struct elf *elf) | ||
12204 | list_del(&sec->list); | ||
12205 | free(sec); | ||
12206 | } | ||
12207 | - if (elf->name) | ||
12208 | - free(elf->name); | ||
12209 | - if (elf->fd > 0) | ||
12210 | - close(elf->fd); | ||
12211 | - if (elf->elf) | ||
12212 | - elf_end(elf->elf); | ||
12213 | + | ||
12214 | free(elf); | ||
12215 | } | ||
12216 | diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h | ||
12217 | index 731973e1a3f5..de5cd2ddded9 100644 | ||
12218 | --- a/tools/objtool/elf.h | ||
12219 | +++ b/tools/objtool/elf.h | ||
12220 | @@ -28,6 +28,13 @@ | ||
12221 | # define elf_getshdrstrndx elf_getshstrndx | ||
12222 | #endif | ||
12223 | |||
12224 | +/* | ||
12225 | + * Fallback for systems without this "read, mmaping if possible" cmd. | ||
12226 | + */ | ||
12227 | +#ifndef ELF_C_READ_MMAP | ||
12228 | +#define ELF_C_READ_MMAP ELF_C_READ | ||
12229 | +#endif | ||
12230 | + | ||
12231 | struct section { | ||
12232 | struct list_head list; | ||
12233 | GElf_Shdr sh; | ||
12234 | @@ -37,11 +44,11 @@ struct section { | ||
12235 | DECLARE_HASHTABLE(rela_hash, 16); | ||
12236 | struct section *base, *rela; | ||
12237 | struct symbol *sym; | ||
12238 | - Elf_Data *elf_data; | ||
12239 | + Elf_Data *data; | ||
12240 | char *name; | ||
12241 | int idx; | ||
12242 | - unsigned long data; | ||
12243 | unsigned int len; | ||
12244 | + bool changed, text; | ||
12245 | }; | ||
12246 | |||
12247 | struct symbol { | ||
12248 | @@ -54,6 +61,7 @@ struct symbol { | ||
12249 | unsigned char bind, type; | ||
12250 | unsigned long offset; | ||
12251 | unsigned int len; | ||
12252 | + struct symbol *pfunc, *cfunc; | ||
12253 | }; | ||
12254 | |||
12255 | struct rela { | ||
12256 | @@ -76,16 +84,23 @@ struct elf { | ||
12257 | }; | ||
12258 | |||
12259 | |||
12260 | -struct elf *elf_open(const char *name); | ||
12261 | +struct elf *elf_open(const char *name, int flags); | ||
12262 | struct section *find_section_by_name(struct elf *elf, const char *name); | ||
12263 | struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); | ||
12264 | +struct symbol *find_symbol_by_name(struct elf *elf, const char *name); | ||
12265 | struct symbol *find_symbol_containing(struct section *sec, unsigned long offset); | ||
12266 | struct rela *find_rela_by_dest(struct section *sec, unsigned long offset); | ||
12267 | struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, | ||
12268 | unsigned int len); | ||
12269 | struct symbol *find_containing_func(struct section *sec, unsigned long offset); | ||
12270 | +struct section *elf_create_section(struct elf *elf, const char *name, size_t | ||
12271 | + entsize, int nr); | ||
12272 | +struct section *elf_create_rela_section(struct elf *elf, struct section *base); | ||
12273 | +int elf_rebuild_rela_section(struct section *sec); | ||
12274 | +int elf_write(struct elf *elf); | ||
12275 | void elf_close(struct elf *elf); | ||
12276 | |||
12277 | - | ||
12278 | +#define for_each_sec(file, sec) \ | ||
12279 | + list_for_each_entry(sec, &file->elf->sections, list) | ||
12280 | |||
12281 | #endif /* _OBJTOOL_ELF_H */ | ||
12282 | diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c | ||
12283 | index 46c326db4f46..07f329919828 100644 | ||
12284 | --- a/tools/objtool/objtool.c | ||
12285 | +++ b/tools/objtool/objtool.c | ||
12286 | @@ -31,11 +31,10 @@ | ||
12287 | #include <stdlib.h> | ||
12288 | #include <subcmd/exec-cmd.h> | ||
12289 | #include <subcmd/pager.h> | ||
12290 | +#include <linux/kernel.h> | ||
12291 | |||
12292 | #include "builtin.h" | ||
12293 | |||
12294 | -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) | ||
12295 | - | ||
12296 | struct cmd_struct { | ||
12297 | const char *name; | ||
12298 | int (*fn)(int, const char **); | ||
12299 | @@ -43,10 +42,11 @@ struct cmd_struct { | ||
12300 | }; | ||
12301 | |||
12302 | static const char objtool_usage_string[] = | ||
12303 | - "objtool [OPTIONS] COMMAND [ARGS]"; | ||
12304 | + "objtool COMMAND [ARGS]"; | ||
12305 | |||
12306 | static struct cmd_struct objtool_cmds[] = { | ||
12307 | {"check", cmd_check, "Perform stack metadata validation on an object file" }, | ||
12308 | + {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" }, | ||
12309 | }; | ||
12310 | |||
12311 | bool help; | ||
12312 | @@ -70,7 +70,7 @@ static void cmd_usage(void) | ||
12313 | |||
12314 | printf("\n"); | ||
12315 | |||
12316 | - exit(1); | ||
12317 | + exit(129); | ||
12318 | } | ||
12319 | |||
12320 | static void handle_options(int *argc, const char ***argv) | ||
12321 | @@ -86,9 +86,7 @@ static void handle_options(int *argc, const char ***argv) | ||
12322 | break; | ||
12323 | } else { | ||
12324 | fprintf(stderr, "Unknown option: %s\n", cmd); | ||
12325 | - fprintf(stderr, "\n Usage: %s\n", | ||
12326 | - objtool_usage_string); | ||
12327 | - exit(1); | ||
12328 | + cmd_usage(); | ||
12329 | } | ||
12330 | |||
12331 | (*argv)++; | ||
12332 | diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h | ||
12333 | new file mode 100644 | ||
12334 | index 000000000000..b0e92a6d0903 | ||
12335 | --- /dev/null | ||
12336 | +++ b/tools/objtool/orc.h | ||
12337 | @@ -0,0 +1,30 @@ | ||
12338 | +/* | ||
12339 | + * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
12340 | + * | ||
12341 | + * This program is free software; you can redistribute it and/or | ||
12342 | + * modify it under the terms of the GNU General Public License | ||
12343 | + * as published by the Free Software Foundation; either version 2 | ||
12344 | + * of the License, or (at your option) any later version. | ||
12345 | + * | ||
12346 | + * This program is distributed in the hope that it will be useful, | ||
12347 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12348 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12349 | + * GNU General Public License for more details. | ||
12350 | + * | ||
12351 | + * You should have received a copy of the GNU General Public License | ||
12352 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
12353 | + */ | ||
12354 | + | ||
12355 | +#ifndef _ORC_H | ||
12356 | +#define _ORC_H | ||
12357 | + | ||
12358 | +#include <asm/orc_types.h> | ||
12359 | + | ||
12360 | +struct objtool_file; | ||
12361 | + | ||
12362 | +int create_orc(struct objtool_file *file); | ||
12363 | +int create_orc_sections(struct objtool_file *file); | ||
12364 | + | ||
12365 | +int orc_dump(const char *objname); | ||
12366 | + | ||
12367 | +#endif /* _ORC_H */ | ||
12368 | diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c | ||
12369 | new file mode 100644 | ||
12370 | index 000000000000..c3343820916a | ||
12371 | --- /dev/null | ||
12372 | +++ b/tools/objtool/orc_dump.c | ||
12373 | @@ -0,0 +1,213 @@ | ||
12374 | +/* | ||
12375 | + * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
12376 | + * | ||
12377 | + * This program is free software; you can redistribute it and/or | ||
12378 | + * modify it under the terms of the GNU General Public License | ||
12379 | + * as published by the Free Software Foundation; either version 2 | ||
12380 | + * of the License, or (at your option) any later version. | ||
12381 | + * | ||
12382 | + * This program is distributed in the hope that it will be useful, | ||
12383 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12384 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12385 | + * GNU General Public License for more details. | ||
12386 | + * | ||
12387 | + * You should have received a copy of the GNU General Public License | ||
12388 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
12389 | + */ | ||
12390 | + | ||
12391 | +#include <unistd.h> | ||
12392 | +#include "orc.h" | ||
12393 | +#include "warn.h" | ||
12394 | + | ||
12395 | +static const char *reg_name(unsigned int reg) | ||
12396 | +{ | ||
12397 | + switch (reg) { | ||
12398 | + case ORC_REG_PREV_SP: | ||
12399 | + return "prevsp"; | ||
12400 | + case ORC_REG_DX: | ||
12401 | + return "dx"; | ||
12402 | + case ORC_REG_DI: | ||
12403 | + return "di"; | ||
12404 | + case ORC_REG_BP: | ||
12405 | + return "bp"; | ||
12406 | + case ORC_REG_SP: | ||
12407 | + return "sp"; | ||
12408 | + case ORC_REG_R10: | ||
12409 | + return "r10"; | ||
12410 | + case ORC_REG_R13: | ||
12411 | + return "r13"; | ||
12412 | + case ORC_REG_BP_INDIRECT: | ||
12413 | + return "bp(ind)"; | ||
12414 | + case ORC_REG_SP_INDIRECT: | ||
12415 | + return "sp(ind)"; | ||
12416 | + default: | ||
12417 | + return "?"; | ||
12418 | + } | ||
12419 | +} | ||
12420 | + | ||
12421 | +static const char *orc_type_name(unsigned int type) | ||
12422 | +{ | ||
12423 | + switch (type) { | ||
12424 | + case ORC_TYPE_CALL: | ||
12425 | + return "call"; | ||
12426 | + case ORC_TYPE_REGS: | ||
12427 | + return "regs"; | ||
12428 | + case ORC_TYPE_REGS_IRET: | ||
12429 | + return "iret"; | ||
12430 | + default: | ||
12431 | + return "?"; | ||
12432 | + } | ||
12433 | +} | ||
12434 | + | ||
12435 | +static void print_reg(unsigned int reg, int offset) | ||
12436 | +{ | ||
12437 | + if (reg == ORC_REG_BP_INDIRECT) | ||
12438 | + printf("(bp%+d)", offset); | ||
12439 | + else if (reg == ORC_REG_SP_INDIRECT) | ||
12440 | + printf("(sp%+d)", offset); | ||
12441 | + else if (reg == ORC_REG_UNDEFINED) | ||
12442 | + printf("(und)"); | ||
12443 | + else | ||
12444 | + printf("%s%+d", reg_name(reg), offset); | ||
12445 | +} | ||
12446 | + | ||
12447 | +int orc_dump(const char *_objname) | ||
12448 | +{ | ||
12449 | + int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0; | ||
12450 | + struct orc_entry *orc = NULL; | ||
12451 | + char *name; | ||
12452 | + size_t nr_sections; | ||
12453 | + Elf64_Addr orc_ip_addr = 0; | ||
12454 | + size_t shstrtab_idx; | ||
12455 | + Elf *elf; | ||
12456 | + Elf_Scn *scn; | ||
12457 | + GElf_Shdr sh; | ||
12458 | + GElf_Rela rela; | ||
12459 | + GElf_Sym sym; | ||
12460 | + Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL; | ||
12461 | + | ||
12462 | + | ||
12463 | + objname = _objname; | ||
12464 | + | ||
12465 | + elf_version(EV_CURRENT); | ||
12466 | + | ||
12467 | + fd = open(objname, O_RDONLY); | ||
12468 | + if (fd == -1) { | ||
12469 | + perror("open"); | ||
12470 | + return -1; | ||
12471 | + } | ||
12472 | + | ||
12473 | + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | ||
12474 | + if (!elf) { | ||
12475 | + WARN_ELF("elf_begin"); | ||
12476 | + return -1; | ||
12477 | + } | ||
12478 | + | ||
12479 | + if (elf_getshdrnum(elf, &nr_sections)) { | ||
12480 | + WARN_ELF("elf_getshdrnum"); | ||
12481 | + return -1; | ||
12482 | + } | ||
12483 | + | ||
12484 | + if (elf_getshdrstrndx(elf, &shstrtab_idx)) { | ||
12485 | + WARN_ELF("elf_getshdrstrndx"); | ||
12486 | + return -1; | ||
12487 | + } | ||
12488 | + | ||
12489 | + for (i = 0; i < nr_sections; i++) { | ||
12490 | + scn = elf_getscn(elf, i); | ||
12491 | + if (!scn) { | ||
12492 | + WARN_ELF("elf_getscn"); | ||
12493 | + return -1; | ||
12494 | + } | ||
12495 | + | ||
12496 | + if (!gelf_getshdr(scn, &sh)) { | ||
12497 | + WARN_ELF("gelf_getshdr"); | ||
12498 | + return -1; | ||
12499 | + } | ||
12500 | + | ||
12501 | + name = elf_strptr(elf, shstrtab_idx, sh.sh_name); | ||
12502 | + if (!name) { | ||
12503 | + WARN_ELF("elf_strptr"); | ||
12504 | + return -1; | ||
12505 | + } | ||
12506 | + | ||
12507 | + data = elf_getdata(scn, NULL); | ||
12508 | + if (!data) { | ||
12509 | + WARN_ELF("elf_getdata"); | ||
12510 | + return -1; | ||
12511 | + } | ||
12512 | + | ||
12513 | + if (!strcmp(name, ".symtab")) { | ||
12514 | + symtab = data; | ||
12515 | + } else if (!strcmp(name, ".orc_unwind")) { | ||
12516 | + orc = data->d_buf; | ||
12517 | + orc_size = sh.sh_size; | ||
12518 | + } else if (!strcmp(name, ".orc_unwind_ip")) { | ||
12519 | + orc_ip = data->d_buf; | ||
12520 | + orc_ip_addr = sh.sh_addr; | ||
12521 | + } else if (!strcmp(name, ".rela.orc_unwind_ip")) { | ||
12522 | + rela_orc_ip = data; | ||
12523 | + } | ||
12524 | + } | ||
12525 | + | ||
12526 | + if (!symtab || !orc || !orc_ip) | ||
12527 | + return 0; | ||
12528 | + | ||
12529 | + if (orc_size % sizeof(*orc) != 0) { | ||
12530 | + WARN("bad .orc_unwind section size"); | ||
12531 | + return -1; | ||
12532 | + } | ||
12533 | + | ||
12534 | + nr_entries = orc_size / sizeof(*orc); | ||
12535 | + for (i = 0; i < nr_entries; i++) { | ||
12536 | + if (rela_orc_ip) { | ||
12537 | + if (!gelf_getrela(rela_orc_ip, i, &rela)) { | ||
12538 | + WARN_ELF("gelf_getrela"); | ||
12539 | + return -1; | ||
12540 | + } | ||
12541 | + | ||
12542 | + if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) { | ||
12543 | + WARN_ELF("gelf_getsym"); | ||
12544 | + return -1; | ||
12545 | + } | ||
12546 | + | ||
12547 | + scn = elf_getscn(elf, sym.st_shndx); | ||
12548 | + if (!scn) { | ||
12549 | + WARN_ELF("elf_getscn"); | ||
12550 | + return -1; | ||
12551 | + } | ||
12552 | + | ||
12553 | + if (!gelf_getshdr(scn, &sh)) { | ||
12554 | + WARN_ELF("gelf_getshdr"); | ||
12555 | + return -1; | ||
12556 | + } | ||
12557 | + | ||
12558 | + name = elf_strptr(elf, shstrtab_idx, sh.sh_name); | ||
12559 | + if (!name || !*name) { | ||
12560 | + WARN_ELF("elf_strptr"); | ||
12561 | + return -1; | ||
12562 | + } | ||
12563 | + | ||
12564 | + printf("%s+%llx:", name, (unsigned long long)rela.r_addend); | ||
12565 | + | ||
12566 | + } else { | ||
12567 | + printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i])); | ||
12568 | + } | ||
12569 | + | ||
12570 | + | ||
12571 | + printf(" sp:"); | ||
12572 | + | ||
12573 | + print_reg(orc[i].sp_reg, orc[i].sp_offset); | ||
12574 | + | ||
12575 | + printf(" bp:"); | ||
12576 | + | ||
12577 | + print_reg(orc[i].bp_reg, orc[i].bp_offset); | ||
12578 | + | ||
12579 | + printf(" type:%s\n", orc_type_name(orc[i].type)); | ||
12580 | + } | ||
12581 | + | ||
12582 | + elf_end(elf); | ||
12583 | + close(fd); | ||
12584 | + | ||
12585 | + return 0; | ||
12586 | +} | ||
12587 | diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c | ||
12588 | new file mode 100644 | ||
12589 | index 000000000000..18384d9be4e1 | ||
12590 | --- /dev/null | ||
12591 | +++ b/tools/objtool/orc_gen.c | ||
12592 | @@ -0,0 +1,221 @@ | ||
12593 | +/* | ||
12594 | + * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
12595 | + * | ||
12596 | + * This program is free software; you can redistribute it and/or | ||
12597 | + * modify it under the terms of the GNU General Public License | ||
12598 | + * as published by the Free Software Foundation; either version 2 | ||
12599 | + * of the License, or (at your option) any later version. | ||
12600 | + * | ||
12601 | + * This program is distributed in the hope that it will be useful, | ||
12602 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12603 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12604 | + * GNU General Public License for more details. | ||
12605 | + * | ||
12606 | + * You should have received a copy of the GNU General Public License | ||
12607 | + * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
12608 | + */ | ||
12609 | + | ||
12610 | +#include <stdlib.h> | ||
12611 | +#include <string.h> | ||
12612 | + | ||
12613 | +#include "orc.h" | ||
12614 | +#include "check.h" | ||
12615 | +#include "warn.h" | ||
12616 | + | ||
12617 | +int create_orc(struct objtool_file *file) | ||
12618 | +{ | ||
12619 | + struct instruction *insn; | ||
12620 | + | ||
12621 | + for_each_insn(file, insn) { | ||
12622 | + struct orc_entry *orc = &insn->orc; | ||
12623 | + struct cfi_reg *cfa = &insn->state.cfa; | ||
12624 | + struct cfi_reg *bp = &insn->state.regs[CFI_BP]; | ||
12625 | + | ||
12626 | + if (cfa->base == CFI_UNDEFINED) { | ||
12627 | + orc->sp_reg = ORC_REG_UNDEFINED; | ||
12628 | + continue; | ||
12629 | + } | ||
12630 | + | ||
12631 | + switch (cfa->base) { | ||
12632 | + case CFI_SP: | ||
12633 | + orc->sp_reg = ORC_REG_SP; | ||
12634 | + break; | ||
12635 | + case CFI_SP_INDIRECT: | ||
12636 | + orc->sp_reg = ORC_REG_SP_INDIRECT; | ||
12637 | + break; | ||
12638 | + case CFI_BP: | ||
12639 | + orc->sp_reg = ORC_REG_BP; | ||
12640 | + break; | ||
12641 | + case CFI_BP_INDIRECT: | ||
12642 | + orc->sp_reg = ORC_REG_BP_INDIRECT; | ||
12643 | + break; | ||
12644 | + case CFI_R10: | ||
12645 | + orc->sp_reg = ORC_REG_R10; | ||
12646 | + break; | ||
12647 | + case CFI_R13: | ||
12648 | + orc->sp_reg = ORC_REG_R13; | ||
12649 | + break; | ||
12650 | + case CFI_DI: | ||
12651 | + orc->sp_reg = ORC_REG_DI; | ||
12652 | + break; | ||
12653 | + case CFI_DX: | ||
12654 | + orc->sp_reg = ORC_REG_DX; | ||
12655 | + break; | ||
12656 | + default: | ||
12657 | + WARN_FUNC("unknown CFA base reg %d", | ||
12658 | + insn->sec, insn->offset, cfa->base); | ||
12659 | + return -1; | ||
12660 | + } | ||
12661 | + | ||
12662 | + switch(bp->base) { | ||
12663 | + case CFI_UNDEFINED: | ||
12664 | + orc->bp_reg = ORC_REG_UNDEFINED; | ||
12665 | + break; | ||
12666 | + case CFI_CFA: | ||
12667 | + orc->bp_reg = ORC_REG_PREV_SP; | ||
12668 | + break; | ||
12669 | + case CFI_BP: | ||
12670 | + orc->bp_reg = ORC_REG_BP; | ||
12671 | + break; | ||
12672 | + default: | ||
12673 | + WARN_FUNC("unknown BP base reg %d", | ||
12674 | + insn->sec, insn->offset, bp->base); | ||
12675 | + return -1; | ||
12676 | + } | ||
12677 | + | ||
12678 | + orc->sp_offset = cfa->offset; | ||
12679 | + orc->bp_offset = bp->offset; | ||
12680 | + orc->type = insn->state.type; | ||
12681 | + } | ||
12682 | + | ||
12683 | + return 0; | ||
12684 | +} | ||
12685 | + | ||
12686 | +static int create_orc_entry(struct section *u_sec, struct section *ip_relasec, | ||
12687 | + unsigned int idx, struct section *insn_sec, | ||
12688 | + unsigned long insn_off, struct orc_entry *o) | ||
12689 | +{ | ||
12690 | + struct orc_entry *orc; | ||
12691 | + struct rela *rela; | ||
12692 | + | ||
12693 | + if (!insn_sec->sym) { | ||
12694 | + WARN("missing symbol for section %s", insn_sec->name); | ||
12695 | + return -1; | ||
12696 | + } | ||
12697 | + | ||
12698 | + /* populate ORC data */ | ||
12699 | + orc = (struct orc_entry *)u_sec->data->d_buf + idx; | ||
12700 | + memcpy(orc, o, sizeof(*orc)); | ||
12701 | + | ||
12702 | + /* populate rela for ip */ | ||
12703 | + rela = malloc(sizeof(*rela)); | ||
12704 | + if (!rela) { | ||
12705 | + perror("malloc"); | ||
12706 | + return -1; | ||
12707 | + } | ||
12708 | + memset(rela, 0, sizeof(*rela)); | ||
12709 | + | ||
12710 | + rela->sym = insn_sec->sym; | ||
12711 | + rela->addend = insn_off; | ||
12712 | + rela->type = R_X86_64_PC32; | ||
12713 | + rela->offset = idx * sizeof(int); | ||
12714 | + | ||
12715 | + list_add_tail(&rela->list, &ip_relasec->rela_list); | ||
12716 | + hash_add(ip_relasec->rela_hash, &rela->hash, rela->offset); | ||
12717 | + | ||
12718 | + return 0; | ||
12719 | +} | ||
12720 | + | ||
12721 | +int create_orc_sections(struct objtool_file *file) | ||
12722 | +{ | ||
12723 | + struct instruction *insn, *prev_insn; | ||
12724 | + struct section *sec, *u_sec, *ip_relasec; | ||
12725 | + unsigned int idx; | ||
12726 | + | ||
12727 | + struct orc_entry empty = { | ||
12728 | + .sp_reg = ORC_REG_UNDEFINED, | ||
12729 | + .bp_reg = ORC_REG_UNDEFINED, | ||
12730 | + .type = ORC_TYPE_CALL, | ||
12731 | + }; | ||
12732 | + | ||
12733 | + sec = find_section_by_name(file->elf, ".orc_unwind"); | ||
12734 | + if (sec) { | ||
12735 | + WARN("file already has .orc_unwind section, skipping"); | ||
12736 | + return -1; | ||
12737 | + } | ||
12738 | + | ||
12739 | + /* count the number of needed orcs */ | ||
12740 | + idx = 0; | ||
12741 | + for_each_sec(file, sec) { | ||
12742 | + if (!sec->text) | ||
12743 | + continue; | ||
12744 | + | ||
12745 | + prev_insn = NULL; | ||
12746 | + sec_for_each_insn(file, sec, insn) { | ||
12747 | + if (!prev_insn || | ||
12748 | + memcmp(&insn->orc, &prev_insn->orc, | ||
12749 | + sizeof(struct orc_entry))) { | ||
12750 | + idx++; | ||
12751 | + } | ||
12752 | + prev_insn = insn; | ||
12753 | + } | ||
12754 | + | ||
12755 | + /* section terminator */ | ||
12756 | + if (prev_insn) | ||
12757 | + idx++; | ||
12758 | + } | ||
12759 | + if (!idx) | ||
12760 | + return -1; | ||
12761 | + | ||
12762 | + | ||
12763 | + /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */ | ||
12764 | + sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx); | ||
12765 | + if (!sec) | ||
12766 | + return -1; | ||
12767 | + | ||
12768 | + ip_relasec = elf_create_rela_section(file->elf, sec); | ||
12769 | + if (!ip_relasec) | ||
12770 | + return -1; | ||
12771 | + | ||
12772 | + /* create .orc_unwind section */ | ||
12773 | + u_sec = elf_create_section(file->elf, ".orc_unwind", | ||
12774 | + sizeof(struct orc_entry), idx); | ||
12775 | + | ||
12776 | + /* populate sections */ | ||
12777 | + idx = 0; | ||
12778 | + for_each_sec(file, sec) { | ||
12779 | + if (!sec->text) | ||
12780 | + continue; | ||
12781 | + | ||
12782 | + prev_insn = NULL; | ||
12783 | + sec_for_each_insn(file, sec, insn) { | ||
12784 | + if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc, | ||
12785 | + sizeof(struct orc_entry))) { | ||
12786 | + | ||
12787 | + if (create_orc_entry(u_sec, ip_relasec, idx, | ||
12788 | + insn->sec, insn->offset, | ||
12789 | + &insn->orc)) | ||
12790 | + return -1; | ||
12791 | + | ||
12792 | + idx++; | ||
12793 | + } | ||
12794 | + prev_insn = insn; | ||
12795 | + } | ||
12796 | + | ||
12797 | + /* section terminator */ | ||
12798 | + if (prev_insn) { | ||
12799 | + if (create_orc_entry(u_sec, ip_relasec, idx, | ||
12800 | + prev_insn->sec, | ||
12801 | + prev_insn->offset + prev_insn->len, | ||
12802 | + &empty)) | ||
12803 | + return -1; | ||
12804 | + | ||
12805 | + idx++; | ||
12806 | + } | ||
12807 | + } | ||
12808 | + | ||
12809 | + if (elf_rebuild_rela_section(ip_relasec)) | ||
12810 | + return -1; | ||
12811 | + | ||
12812 | + return 0; | ||
12813 | +} | ||
12814 | diff --git a/tools/objtool/special.c b/tools/objtool/special.c | ||
12815 | index bff8abb3a4aa..84f001d52322 100644 | ||
12816 | --- a/tools/objtool/special.c | ||
12817 | +++ b/tools/objtool/special.c | ||
12818 | @@ -91,16 +91,16 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, | ||
12819 | alt->jump_or_nop = entry->jump_or_nop; | ||
12820 | |||
12821 | if (alt->group) { | ||
12822 | - alt->orig_len = *(unsigned char *)(sec->data + offset + | ||
12823 | + alt->orig_len = *(unsigned char *)(sec->data->d_buf + offset + | ||
12824 | entry->orig_len); | ||
12825 | - alt->new_len = *(unsigned char *)(sec->data + offset + | ||
12826 | + alt->new_len = *(unsigned char *)(sec->data->d_buf + offset + | ||
12827 | entry->new_len); | ||
12828 | } | ||
12829 | |||
12830 | if (entry->feature) { | ||
12831 | unsigned short feature; | ||
12832 | |||
12833 | - feature = *(unsigned short *)(sec->data + offset + | ||
12834 | + feature = *(unsigned short *)(sec->data->d_buf + offset + | ||
12835 | entry->feature); | ||
12836 | |||
12837 | /* | ||
12838 | diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh | ||
12839 | new file mode 100755 | ||
12840 | index 000000000000..1470e74e9d66 | ||
12841 | --- /dev/null | ||
12842 | +++ b/tools/objtool/sync-check.sh | ||
12843 | @@ -0,0 +1,29 @@ | ||
12844 | +#!/bin/sh | ||
12845 | +# SPDX-License-Identifier: GPL-2.0 | ||
12846 | + | ||
12847 | +FILES=' | ||
12848 | +arch/x86/lib/insn.c | ||
12849 | +arch/x86/lib/inat.c | ||
12850 | +arch/x86/lib/x86-opcode-map.txt | ||
12851 | +arch/x86/tools/gen-insn-attr-x86.awk | ||
12852 | +arch/x86/include/asm/insn.h | ||
12853 | +arch/x86/include/asm/inat.h | ||
12854 | +arch/x86/include/asm/inat_types.h | ||
12855 | +arch/x86/include/asm/orc_types.h | ||
12856 | +' | ||
12857 | + | ||
12858 | +check() | ||
12859 | +{ | ||
12860 | + local file=$1 | ||
12861 | + | ||
12862 | + diff $file ../../$file > /dev/null || | ||
12863 | + echo "Warning: synced file at 'tools/objtool/$file' differs from latest kernel version at '$file'" | ||
12864 | +} | ||
12865 | + | ||
12866 | +if [ ! -d ../../kernel ] || [ ! -d ../../tools ] || [ ! -d ../objtool ]; then | ||
12867 | + exit 0 | ||
12868 | +fi | ||
12869 | + | ||
12870 | +for i in $FILES; do | ||
12871 | + check $i | ||
12872 | +done | ||
12873 | diff --git a/tools/objtool/warn.h b/tools/objtool/warn.h | ||
12874 | index ac7e07523e84..afd9f7a05f6d 100644 | ||
12875 | --- a/tools/objtool/warn.h | ||
12876 | +++ b/tools/objtool/warn.h | ||
12877 | @@ -18,6 +18,13 @@ | ||
12878 | #ifndef _WARN_H | ||
12879 | #define _WARN_H | ||
12880 | |||
12881 | +#include <stdlib.h> | ||
12882 | +#include <string.h> | ||
12883 | +#include <sys/types.h> | ||
12884 | +#include <sys/stat.h> | ||
12885 | +#include <fcntl.h> | ||
12886 | +#include "elf.h" | ||
12887 | + | ||
12888 | extern const char *objname; | ||
12889 | |||
12890 | static inline char *offstr(struct section *sec, unsigned long offset) | ||
12891 | @@ -57,4 +64,7 @@ static inline char *offstr(struct section *sec, unsigned long offset) | ||
12892 | free(_str); \ | ||
12893 | }) | ||
12894 | |||
12895 | +#define WARN_ELF(format, ...) \ | ||
12896 | + WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) | ||
12897 | + | ||
12898 | #endif /* _WARN_H */ | ||
12899 | diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST | ||
12900 | index 0bda2cca2b3a..a4f98e131819 100644 | ||
12901 | --- a/tools/perf/MANIFEST | ||
12902 | +++ b/tools/perf/MANIFEST | ||
12903 | @@ -51,6 +51,7 @@ tools/include/asm-generic/bitops/arch_hweight.h | ||
12904 | tools/include/asm-generic/bitops/atomic.h | ||
12905 | tools/include/asm-generic/bitops/const_hweight.h | ||
12906 | tools/include/asm-generic/bitops/__ffs.h | ||
12907 | +tools/include/asm-generic/bitops/__ffz.h | ||
12908 | tools/include/asm-generic/bitops/__fls.h | ||
12909 | tools/include/asm-generic/bitops/find.h | ||
12910 | tools/include/asm-generic/bitops/fls64.h | ||
12911 | @@ -60,7 +61,9 @@ tools/include/asm-generic/bitops.h | ||
12912 | tools/include/linux/atomic.h | ||
12913 | tools/include/linux/bitops.h | ||
12914 | tools/include/linux/compiler.h | ||
12915 | +tools/include/linux/compiler-gcc.h | ||
12916 | tools/include/linux/coresight-pmu.h | ||
12917 | +tools/include/linux/bug.h | ||
12918 | tools/include/linux/filter.h | ||
12919 | tools/include/linux/hash.h | ||
12920 | tools/include/linux/kernel.h | ||
12921 | @@ -70,12 +73,15 @@ tools/include/uapi/asm-generic/mman-common.h | ||
12922 | tools/include/uapi/asm-generic/mman.h | ||
12923 | tools/include/uapi/linux/bpf.h | ||
12924 | tools/include/uapi/linux/bpf_common.h | ||
12925 | +tools/include/uapi/linux/fcntl.h | ||
12926 | tools/include/uapi/linux/hw_breakpoint.h | ||
12927 | tools/include/uapi/linux/mman.h | ||
12928 | tools/include/uapi/linux/perf_event.h | ||
12929 | +tools/include/uapi/linux/stat.h | ||
12930 | tools/include/linux/poison.h | ||
12931 | tools/include/linux/rbtree.h | ||
12932 | tools/include/linux/rbtree_augmented.h | ||
12933 | +tools/include/linux/refcount.h | ||
12934 | tools/include/linux/string.h | ||
12935 | tools/include/linux/stringify.h | ||
12936 | tools/include/linux/types.h | ||
12937 | diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf | ||
12938 | index 2b92ffef554b..ad3726c5754d 100644 | ||
12939 | --- a/tools/perf/Makefile.perf | ||
12940 | +++ b/tools/perf/Makefile.perf | ||
12941 | @@ -177,6 +177,36 @@ ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),) | ||
12942 | endif | ||
12943 | endif | ||
12944 | |||
12945 | +# The fixdep build - we force fixdep tool to be built as | ||
12946 | +# the first target in the separate make session not to be | ||
12947 | +# disturbed by any parallel make jobs. Once fixdep is done | ||
12948 | +# we issue the requested build with FIXDEP=1 variable. | ||
12949 | +# | ||
12950 | +# The fixdep build is disabled for $(NON_CONFIG_TARGETS) | ||
12951 | +# targets, because it's not necessary. | ||
12952 | + | ||
12953 | +ifdef FIXDEP | ||
12954 | + force_fixdep := 0 | ||
12955 | +else | ||
12956 | + force_fixdep := $(config) | ||
12957 | +endif | ||
12958 | + | ||
12959 | +export srctree OUTPUT RM CC CXX LD AR CFLAGS CXXFLAGS V BISON FLEX AWK | ||
12960 | +export HOSTCC HOSTLD HOSTAR | ||
12961 | + | ||
12962 | +include $(srctree)/tools/build/Makefile.include | ||
12963 | + | ||
12964 | +ifeq ($(force_fixdep),1) | ||
12965 | +goals := $(filter-out all sub-make, $(MAKECMDGOALS)) | ||
12966 | + | ||
12967 | +$(goals) all: sub-make | ||
12968 | + | ||
12969 | +sub-make: fixdep | ||
12970 | + @./check-headers.sh | ||
12971 | + $(Q)$(MAKE) FIXDEP=1 -f Makefile.perf $(goals) | ||
12972 | + | ||
12973 | +else # force_fixdep | ||
12974 | + | ||
12975 | # Set FEATURE_TESTS to 'all' so all possible feature checkers are executed. | ||
12976 | # Without this setting the output feature dump file misses some features, for | ||
12977 | # example, liberty. Select all checkers so we won't get an incomplete feature | ||
12978 | @@ -348,10 +378,6 @@ strip: $(PROGRAMS) $(OUTPUT)perf | ||
12979 | |||
12980 | PERF_IN := $(OUTPUT)perf-in.o | ||
12981 | |||
12982 | -export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK | ||
12983 | -export HOSTCC HOSTLD HOSTAR | ||
12984 | -include $(srctree)/tools/build/Makefile.include | ||
12985 | - | ||
12986 | JEVENTS := $(OUTPUT)pmu-events/jevents | ||
12987 | JEVENTS_IN := $(OUTPUT)pmu-events/jevents-in.o | ||
12988 | |||
12989 | @@ -362,99 +388,6 @@ export JEVENTS | ||
12990 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | ||
12991 | |||
12992 | $(PERF_IN): prepare FORCE | ||
12993 | - @(test -f ../../include/uapi/linux/perf_event.h && ( \ | ||
12994 | - (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \ | ||
12995 | - || echo "Warning: tools/include/uapi/linux/perf_event.h differs from kernel" >&2 )) || true | ||
12996 | - @(test -f ../../include/linux/hash.h && ( \ | ||
12997 | - (diff -B ../include/linux/hash.h ../../include/linux/hash.h >/dev/null) \ | ||
12998 | - || echo "Warning: tools/include/linux/hash.h differs from kernel" >&2 )) || true | ||
12999 | - @(test -f ../../include/uapi/linux/hw_breakpoint.h && ( \ | ||
13000 | - (diff -B ../include/uapi/linux/hw_breakpoint.h ../../include/uapi/linux/hw_breakpoint.h >/dev/null) \ | ||
13001 | - || echo "Warning: tools/include/uapi/linux/hw_breakpoint.h differs from kernel" >&2 )) || true | ||
13002 | - @(test -f ../../arch/x86/include/asm/disabled-features.h && ( \ | ||
13003 | - (diff -B ../arch/x86/include/asm/disabled-features.h ../../arch/x86/include/asm/disabled-features.h >/dev/null) \ | ||
13004 | - || echo "Warning: tools/arch/x86/include/asm/disabled-features.h differs from kernel" >&2 )) || true | ||
13005 | - @(test -f ../../arch/x86/include/asm/required-features.h && ( \ | ||
13006 | - (diff -B ../arch/x86/include/asm/required-features.h ../../arch/x86/include/asm/required-features.h >/dev/null) \ | ||
13007 | - || echo "Warning: tools/arch/x86/include/asm/required-features.h differs from kernel" >&2 )) || true | ||
13008 | - @(test -f ../../arch/x86/include/asm/cpufeatures.h && ( \ | ||
13009 | - (diff -B ../arch/x86/include/asm/cpufeatures.h ../../arch/x86/include/asm/cpufeatures.h >/dev/null) \ | ||
13010 | - || echo "Warning: tools/arch/x86/include/asm/cpufeatures.h differs from kernel" >&2 )) || true | ||
13011 | - @(test -f ../../arch/x86/lib/memcpy_64.S && ( \ | ||
13012 | - (diff -B ../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memcpy_64.S >/dev/null) \ | ||
13013 | - || echo "Warning: tools/arch/x86/lib/memcpy_64.S differs from kernel" >&2 )) || true | ||
13014 | - @(test -f ../../arch/x86/lib/memset_64.S && ( \ | ||
13015 | - (diff -B ../arch/x86/lib/memset_64.S ../../arch/x86/lib/memset_64.S >/dev/null) \ | ||
13016 | - || echo "Warning: tools/arch/x86/lib/memset_64.S differs from kernel" >&2 )) || true | ||
13017 | - @(test -f ../../arch/arm/include/uapi/asm/perf_regs.h && ( \ | ||
13018 | - (diff -B ../arch/arm/include/uapi/asm/perf_regs.h ../../arch/arm/include/uapi/asm/perf_regs.h >/dev/null) \ | ||
13019 | - || echo "Warning: tools/arch/arm/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true | ||
13020 | - @(test -f ../../arch/arm64/include/uapi/asm/perf_regs.h && ( \ | ||
13021 | - (diff -B ../arch/arm64/include/uapi/asm/perf_regs.h ../../arch/arm64/include/uapi/asm/perf_regs.h >/dev/null) \ | ||
13022 | - || echo "Warning: tools/arch/arm64/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true | ||
13023 | - @(test -f ../../arch/powerpc/include/uapi/asm/perf_regs.h && ( \ | ||
13024 | - (diff -B ../arch/powerpc/include/uapi/asm/perf_regs.h ../../arch/powerpc/include/uapi/asm/perf_regs.h >/dev/null) \ | ||
13025 | - || echo "Warning: tools/arch/powerpc/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true | ||
13026 | - @(test -f ../../arch/x86/include/uapi/asm/perf_regs.h && ( \ | ||
13027 | - (diff -B ../arch/x86/include/uapi/asm/perf_regs.h ../../arch/x86/include/uapi/asm/perf_regs.h >/dev/null) \ | ||
13028 | - || echo "Warning: tools/arch/x86/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true | ||
13029 | - @(test -f ../../arch/x86/include/uapi/asm/kvm.h && ( \ | ||
13030 | - (diff -B ../arch/x86/include/uapi/asm/kvm.h ../../arch/x86/include/uapi/asm/kvm.h >/dev/null) \ | ||
13031 | - || echo "Warning: tools/arch/x86/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
13032 | - @(test -f ../../arch/x86/include/uapi/asm/kvm_perf.h && ( \ | ||
13033 | - (diff -B ../arch/x86/include/uapi/asm/kvm_perf.h ../../arch/x86/include/uapi/asm/kvm_perf.h >/dev/null) \ | ||
13034 | - || echo "Warning: tools/arch/x86/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true | ||
13035 | - @(test -f ../../arch/x86/include/uapi/asm/svm.h && ( \ | ||
13036 | - (diff -B ../arch/x86/include/uapi/asm/svm.h ../../arch/x86/include/uapi/asm/svm.h >/dev/null) \ | ||
13037 | - || echo "Warning: tools/arch/x86/include/uapi/asm/svm.h differs from kernel" >&2 )) || true | ||
13038 | - @(test -f ../../arch/x86/include/uapi/asm/vmx.h && ( \ | ||
13039 | - (diff -B ../arch/x86/include/uapi/asm/vmx.h ../../arch/x86/include/uapi/asm/vmx.h >/dev/null) \ | ||
13040 | - || echo "Warning: tools/arch/x86/include/uapi/asm/vmx.h differs from kernel" >&2 )) || true | ||
13041 | - @(test -f ../../arch/powerpc/include/uapi/asm/kvm.h && ( \ | ||
13042 | - (diff -B ../arch/powerpc/include/uapi/asm/kvm.h ../../arch/powerpc/include/uapi/asm/kvm.h >/dev/null) \ | ||
13043 | - || echo "Warning: tools/arch/powerpc/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
13044 | - @(test -f ../../arch/s390/include/uapi/asm/kvm.h && ( \ | ||
13045 | - (diff -B ../arch/s390/include/uapi/asm/kvm.h ../../arch/s390/include/uapi/asm/kvm.h >/dev/null) \ | ||
13046 | - || echo "Warning: tools/arch/s390/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
13047 | - @(test -f ../../arch/s390/include/uapi/asm/kvm_perf.h && ( \ | ||
13048 | - (diff -B ../arch/s390/include/uapi/asm/kvm_perf.h ../../arch/s390/include/uapi/asm/kvm_perf.h >/dev/null) \ | ||
13049 | - || echo "Warning: tools/arch/s390/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true | ||
13050 | - @(test -f ../../arch/s390/include/uapi/asm/sie.h && ( \ | ||
13051 | - (diff -B ../arch/s390/include/uapi/asm/sie.h ../../arch/s390/include/uapi/asm/sie.h >/dev/null) \ | ||
13052 | - || echo "Warning: tools/arch/s390/include/uapi/asm/sie.h differs from kernel" >&2 )) || true | ||
13053 | - @(test -f ../../arch/arm/include/uapi/asm/kvm.h && ( \ | ||
13054 | - (diff -B ../arch/arm/include/uapi/asm/kvm.h ../../arch/arm/include/uapi/asm/kvm.h >/dev/null) \ | ||
13055 | - || echo "Warning: tools/arch/arm/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
13056 | - @(test -f ../../arch/arm64/include/uapi/asm/kvm.h && ( \ | ||
13057 | - (diff -B ../arch/arm64/include/uapi/asm/kvm.h ../../arch/arm64/include/uapi/asm/kvm.h >/dev/null) \ | ||
13058 | - || echo "Warning: tools/arch/arm64/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true | ||
13059 | - @(test -f ../../include/asm-generic/bitops/arch_hweight.h && ( \ | ||
13060 | - (diff -B ../include/asm-generic/bitops/arch_hweight.h ../../include/asm-generic/bitops/arch_hweight.h >/dev/null) \ | ||
13061 | - || echo "Warning: tools/include/asm-generic/bitops/arch_hweight.h differs from kernel" >&2 )) || true | ||
13062 | - @(test -f ../../include/asm-generic/bitops/const_hweight.h && ( \ | ||
13063 | - (diff -B ../include/asm-generic/bitops/const_hweight.h ../../include/asm-generic/bitops/const_hweight.h >/dev/null) \ | ||
13064 | - || echo "Warning: tools/include/asm-generic/bitops/const_hweight.h differs from kernel" >&2 )) || true | ||
13065 | - @(test -f ../../include/asm-generic/bitops/__fls.h && ( \ | ||
13066 | - (diff -B ../include/asm-generic/bitops/__fls.h ../../include/asm-generic/bitops/__fls.h >/dev/null) \ | ||
13067 | - || echo "Warning: tools/include/asm-generic/bitops/__fls.h differs from kernel" >&2 )) || true | ||
13068 | - @(test -f ../../include/asm-generic/bitops/fls.h && ( \ | ||
13069 | - (diff -B ../include/asm-generic/bitops/fls.h ../../include/asm-generic/bitops/fls.h >/dev/null) \ | ||
13070 | - || echo "Warning: tools/include/asm-generic/bitops/fls.h differs from kernel" >&2 )) || true | ||
13071 | - @(test -f ../../include/asm-generic/bitops/fls64.h && ( \ | ||
13072 | - (diff -B ../include/asm-generic/bitops/fls64.h ../../include/asm-generic/bitops/fls64.h >/dev/null) \ | ||
13073 | - || echo "Warning: tools/include/asm-generic/bitops/fls64.h differs from kernel" >&2 )) || true | ||
13074 | - @(test -f ../../include/linux/coresight-pmu.h && ( \ | ||
13075 | - (diff -B ../include/linux/coresight-pmu.h ../../include/linux/coresight-pmu.h >/dev/null) \ | ||
13076 | - || echo "Warning: tools/include/linux/coresight-pmu.h differs from kernel" >&2 )) || true | ||
13077 | - @(test -f ../../include/uapi/asm-generic/mman-common.h && ( \ | ||
13078 | - (diff -B ../include/uapi/asm-generic/mman-common.h ../../include/uapi/asm-generic/mman-common.h >/dev/null) \ | ||
13079 | - || echo "Warning: tools/include/uapi/asm-generic/mman-common.h differs from kernel" >&2 )) || true | ||
13080 | - @(test -f ../../include/uapi/asm-generic/mman.h && ( \ | ||
13081 | - (diff -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>$$" ../include/uapi/asm-generic/mman.h ../../include/uapi/asm-generic/mman.h >/dev/null) \ | ||
13082 | - || echo "Warning: tools/include/uapi/asm-generic/mman.h differs from kernel" >&2 )) || true | ||
13083 | - @(test -f ../../include/uapi/linux/mman.h && ( \ | ||
13084 | - (diff -B -I "^#include <\(uapi/\)*asm/mman.h>$$" ../include/uapi/linux/mman.h ../../include/uapi/linux/mman.h >/dev/null) \ | ||
13085 | - || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true | ||
13086 | $(Q)$(MAKE) $(build)=perf | ||
13087 | |||
13088 | $(JEVENTS_IN): FORCE | ||
13089 | @@ -470,7 +403,7 @@ $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBTRACEEVENT_DYNAMIC_L | ||
13090 | $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ | ||
13091 | $(PERF_IN) $(PMU_EVENTS_IN) $(LIBS) -o $@ | ||
13092 | |||
13093 | -$(GTK_IN): fixdep FORCE | ||
13094 | +$(GTK_IN): FORCE | ||
13095 | $(Q)$(MAKE) $(build)=gtk | ||
13096 | |||
13097 | $(OUTPUT)libperf-gtk.so: $(GTK_IN) $(PERFLIBS) | ||
13098 | @@ -515,7 +448,7 @@ endif | ||
13099 | __build-dir = $(subst $(OUTPUT),,$(dir $@)) | ||
13100 | build-dir = $(if $(__build-dir),$(__build-dir),.) | ||
13101 | |||
13102 | -prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep archheaders | ||
13103 | +prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders | ||
13104 | |||
13105 | $(OUTPUT)%.o: %.c prepare FORCE | ||
13106 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | ||
13107 | @@ -555,7 +488,7 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) | ||
13108 | |||
13109 | LIBPERF_IN := $(OUTPUT)libperf-in.o | ||
13110 | |||
13111 | -$(LIBPERF_IN): prepare fixdep FORCE | ||
13112 | +$(LIBPERF_IN): prepare FORCE | ||
13113 | $(Q)$(MAKE) $(build)=libperf | ||
13114 | |||
13115 | $(LIB_FILE): $(LIBPERF_IN) | ||
13116 | @@ -563,10 +496,10 @@ $(LIB_FILE): $(LIBPERF_IN) | ||
13117 | |||
13118 | LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) | ||
13119 | |||
13120 | -$(LIBTRACEEVENT): fixdep FORCE | ||
13121 | +$(LIBTRACEEVENT): FORCE | ||
13122 | $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a | ||
13123 | |||
13124 | -libtraceevent_plugins: fixdep FORCE | ||
13125 | +libtraceevent_plugins: FORCE | ||
13126 | $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins | ||
13127 | |||
13128 | $(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins | ||
13129 | @@ -579,21 +512,21 @@ $(LIBTRACEEVENT)-clean: | ||
13130 | install-traceevent-plugins: libtraceevent_plugins | ||
13131 | $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins | ||
13132 | |||
13133 | -$(LIBAPI): fixdep FORCE | ||
13134 | +$(LIBAPI): FORCE | ||
13135 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a | ||
13136 | |||
13137 | $(LIBAPI)-clean: | ||
13138 | $(call QUIET_CLEAN, libapi) | ||
13139 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null | ||
13140 | |||
13141 | -$(LIBBPF): fixdep FORCE | ||
13142 | +$(LIBBPF): FORCE | ||
13143 | $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) | ||
13144 | |||
13145 | $(LIBBPF)-clean: | ||
13146 | $(call QUIET_CLEAN, libbpf) | ||
13147 | $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null | ||
13148 | |||
13149 | -$(LIBSUBCMD): fixdep FORCE | ||
13150 | +$(LIBSUBCMD): FORCE | ||
13151 | $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a | ||
13152 | |||
13153 | $(LIBSUBCMD)-clean: | ||
13154 | @@ -790,3 +723,4 @@ FORCE: | ||
13155 | .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare | ||
13156 | .PHONY: libtraceevent_plugins archheaders | ||
13157 | |||
13158 | +endif # force_fixdep | ||
13159 | diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | ||
13160 | index 555263e385c9..e93ef0b38db8 100644 | ||
13161 | --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | ||
13162 | +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | ||
13163 | @@ -335,6 +335,9 @@ | ||
13164 | 326 common copy_file_range sys_copy_file_range | ||
13165 | 327 64 preadv2 sys_preadv2 | ||
13166 | 328 64 pwritev2 sys_pwritev2 | ||
13167 | +329 common pkey_mprotect sys_pkey_mprotect | ||
13168 | +330 common pkey_alloc sys_pkey_alloc | ||
13169 | +331 common pkey_free sys_pkey_free | ||
13170 | |||
13171 | # | ||
13172 | # x32-specific system call numbers start at 512 to avoid cache impact | ||
13173 | @@ -374,5 +377,5 @@ | ||
13174 | 543 x32 io_setup compat_sys_io_setup | ||
13175 | 544 x32 io_submit compat_sys_io_submit | ||
13176 | 545 x32 execveat compat_sys_execveat/ptregs | ||
13177 | -534 x32 preadv2 compat_sys_preadv2 | ||
13178 | -535 x32 pwritev2 compat_sys_pwritev2 | ||
13179 | +546 x32 preadv2 compat_sys_preadv64v2 | ||
13180 | +547 x32 pwritev2 compat_sys_pwritev64v2 | ||
13181 | diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh | ||
13182 | new file mode 100755 | ||
13183 | index 000000000000..83fe2202382e | ||
13184 | --- /dev/null | ||
13185 | +++ b/tools/perf/check-headers.sh | ||
13186 | @@ -0,0 +1,61 @@ | ||
13187 | +#!/bin/sh | ||
13188 | + | ||
13189 | +HEADERS=' | ||
13190 | +include/uapi/linux/fcntl.h | ||
13191 | +include/uapi/linux/perf_event.h | ||
13192 | +include/uapi/linux/stat.h | ||
13193 | +include/linux/hash.h | ||
13194 | +include/uapi/linux/hw_breakpoint.h | ||
13195 | +arch/x86/include/asm/disabled-features.h | ||
13196 | +arch/x86/include/asm/required-features.h | ||
13197 | +arch/x86/include/asm/cpufeatures.h | ||
13198 | +arch/arm/include/uapi/asm/perf_regs.h | ||
13199 | +arch/arm64/include/uapi/asm/perf_regs.h | ||
13200 | +arch/powerpc/include/uapi/asm/perf_regs.h | ||
13201 | +arch/x86/include/uapi/asm/perf_regs.h | ||
13202 | +arch/x86/include/uapi/asm/kvm.h | ||
13203 | +arch/x86/include/uapi/asm/kvm_perf.h | ||
13204 | +arch/x86/include/uapi/asm/svm.h | ||
13205 | +arch/x86/include/uapi/asm/vmx.h | ||
13206 | +arch/powerpc/include/uapi/asm/kvm.h | ||
13207 | +arch/s390/include/uapi/asm/kvm.h | ||
13208 | +arch/s390/include/uapi/asm/kvm_perf.h | ||
13209 | +arch/s390/include/uapi/asm/sie.h | ||
13210 | +arch/arm/include/uapi/asm/kvm.h | ||
13211 | +arch/arm64/include/uapi/asm/kvm.h | ||
13212 | +include/asm-generic/bitops/arch_hweight.h | ||
13213 | +include/asm-generic/bitops/const_hweight.h | ||
13214 | +include/asm-generic/bitops/__fls.h | ||
13215 | +include/asm-generic/bitops/fls.h | ||
13216 | +include/asm-generic/bitops/fls64.h | ||
13217 | +include/linux/coresight-pmu.h | ||
13218 | +include/uapi/asm-generic/mman-common.h | ||
13219 | +' | ||
13220 | + | ||
13221 | +check () { | ||
13222 | + file=$1 | ||
13223 | + opts= | ||
13224 | + | ||
13225 | + shift | ||
13226 | + while [ -n "$*" ]; do | ||
13227 | + opts="$opts \"$1\"" | ||
13228 | + shift | ||
13229 | + done | ||
13230 | + | ||
13231 | + cmd="diff $opts ../$file ../../$file > /dev/null" | ||
13232 | + | ||
13233 | + test -f ../../$file && | ||
13234 | + eval $cmd || echo "Warning: $file differs from kernel" >&2 | ||
13235 | +} | ||
13236 | + | ||
13237 | + | ||
13238 | +# simple diff check | ||
13239 | +for i in $HEADERS; do | ||
13240 | + check $i -B | ||
13241 | +done | ||
13242 | + | ||
13243 | +# diff with extra ignore lines | ||
13244 | +check arch/x86/lib/memcpy_64.S -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" | ||
13245 | +check arch/x86/lib/memset_64.S -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" | ||
13246 | +check include/uapi/asm-generic/mman.h -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>" | ||
13247 | +check include/uapi/linux/mman.h -B -I "^#include <\(uapi/\)*asm/mman.h>" | ||
13248 | diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h | ||
13249 | index 43899e0d6fa1..e72d370889f8 100644 | ||
13250 | --- a/tools/perf/util/util.h | ||
13251 | +++ b/tools/perf/util/util.h | ||
13252 | @@ -23,8 +23,6 @@ | ||
13253 | #endif | ||
13254 | #endif | ||
13255 | |||
13256 | -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) | ||
13257 | - | ||
13258 | #ifdef __GNUC__ | ||
13259 | #define TYPEOF(x) (__typeof__(x)) | ||
13260 | #else |