Contents of /trunk/kernel-alx-legacy/patches-4.9/0205-4.9.106-all-fixes.patch
Parent Directory | Revision Log
Revision 3608 -
(show annotations)
(download)
Fri Aug 14 07:34:29 2020 UTC (4 years, 1 month ago) by niro
File size: 382694 byte(s)
Fri Aug 14 07:34:29 2020 UTC (4 years, 1 month ago) by niro
File size: 382694 byte(s)
-added kerenl-alx-legacy pkg
1 | 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 |