diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.9.21/0088-objtool-sync-up-with-the-4.14.47-version-of-objtool.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.9.21/0088-objtool-sync-up-with-the-4.14.47-version-of-objtool.patch | 9906 |
1 files changed, 0 insertions, 9906 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.9.21/0088-objtool-sync-up-with-the-4.14.47-version-of-objtool.patch b/common/recipes-kernel/linux/linux-yocto-4.9.21/0088-objtool-sync-up-with-the-4.14.47-version-of-objtool.patch deleted file mode 100644 index 318297bf..00000000 --- a/common/recipes-kernel/linux/linux-yocto-4.9.21/0088-objtool-sync-up-with-the-4.14.47-version-of-objtool.patch +++ /dev/null @@ -1,9906 +0,0 @@ -From 0706298ca42f992d0c1afb93c8d6710d15f88ccb Mon Sep 17 00:00:00 2001 -From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -Date: Sun, 3 Jun 2018 12:35:15 +0200 -Subject: [PATCH 88/93] objtool: sync up with the 4.14.47 version of objtool - -There are pros and cons of dealing with tools in the kernel directory. -The pros are the fact that development happens fast, and new features -can be added to the kernel and the tools at the same times. The cons -are when dealing with backported kernel patches, it can be necessary to -backport parts of the tool changes as well. - -For 4.9.y so far, we have backported individual patches. That quickly -breaks down when there are minor differences between how backports were -handled, so grabbing 40+ patch long series can be difficult, not -impossible, but really frustrating to attempt. - -To help mitigate this mess, here's a single big patch to sync up the -objtool logic to the 4.14.47 version of the tool. From this point -forward (after some other minor header file patches are applied), the -tool should be in sync and much easier to maintain over time. - -This has survivied my limited testing, and as the codebase is identical -to 4.14.47, I'm pretty comfortable dropping this big change in here in -4.9.y. Hopefully all goes well... - -Cc: Josh Poimboeuf <jpoimboe@redhat.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> ---- - arch/x86/include/asm/orc_types.h | 107 ++ - arch/x86/include/asm/unwind_hints.h | 103 ++ - tools/objtool/Build | 3 + - tools/objtool/Documentation/stack-validation.txt | 195 ++- - tools/objtool/Makefile | 35 +- - tools/objtool/arch.h | 65 +- - tools/objtool/arch/x86/Build | 10 +- - tools/objtool/arch/x86/decode.c | 408 +++++- - tools/objtool/arch/x86/include/asm/inat.h | 244 ++++ - tools/objtool/arch/x86/include/asm/inat_types.h | 29 + - tools/objtool/arch/x86/include/asm/insn.h | 211 ++++ - tools/objtool/arch/x86/include/asm/orc_types.h | 107 ++ - tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk | 392 ------ - tools/objtool/arch/x86/insn/inat.c | 97 -- - tools/objtool/arch/x86/insn/inat.h | 234 ---- - tools/objtool/arch/x86/insn/inat_types.h | 29 - - tools/objtool/arch/x86/insn/insn.c | 606 --------- - tools/objtool/arch/x86/insn/insn.h | 211 ---- - tools/objtool/arch/x86/insn/x86-opcode-map.txt | 1063 ---------------- - tools/objtool/arch/x86/lib/inat.c | 97 ++ - tools/objtool/arch/x86/lib/insn.c | 606 +++++++++ - tools/objtool/arch/x86/lib/x86-opcode-map.txt | 1072 ++++++++++++++++ - tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk | 393 ++++++ - tools/objtool/builtin-check.c | 9 +- - tools/objtool/builtin-orc.c | 68 + - tools/objtool/builtin.h | 6 + - tools/objtool/cfi.h | 55 + - tools/objtool/check.c | 1329 ++++++++++++++++---- - tools/objtool/check.h | 39 +- - tools/objtool/elf.c | 284 ++++- - tools/objtool/elf.h | 21 +- - tools/objtool/objtool.c | 12 +- - tools/objtool/orc.h | 30 + - tools/objtool/orc_dump.c | 213 ++++ - tools/objtool/orc_gen.c | 221 ++++ - tools/objtool/special.c | 6 +- - tools/objtool/sync-check.sh | 29 + - tools/objtool/warn.h | 10 + - 38 files changed, 5511 insertions(+), 3138 deletions(-) - create mode 100644 arch/x86/include/asm/orc_types.h - create mode 100644 arch/x86/include/asm/unwind_hints.h - create mode 100644 tools/objtool/arch/x86/include/asm/inat.h - create mode 100644 tools/objtool/arch/x86/include/asm/inat_types.h - create mode 100644 tools/objtool/arch/x86/include/asm/insn.h - create mode 100644 tools/objtool/arch/x86/include/asm/orc_types.h - delete mode 100644 tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk - delete mode 100644 tools/objtool/arch/x86/insn/inat.c - delete mode 100644 tools/objtool/arch/x86/insn/inat.h - delete mode 100644 tools/objtool/arch/x86/insn/inat_types.h - delete mode 100644 tools/objtool/arch/x86/insn/insn.c - delete mode 100644 tools/objtool/arch/x86/insn/insn.h - delete mode 100644 tools/objtool/arch/x86/insn/x86-opcode-map.txt - create mode 100644 tools/objtool/arch/x86/lib/inat.c - create mode 100644 tools/objtool/arch/x86/lib/insn.c - create mode 100644 tools/objtool/arch/x86/lib/x86-opcode-map.txt - create mode 100644 tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk - create mode 100644 tools/objtool/builtin-orc.c - create mode 100644 tools/objtool/cfi.h - create mode 100644 tools/objtool/orc.h - create mode 100644 tools/objtool/orc_dump.c - create mode 100644 tools/objtool/orc_gen.c - create mode 100755 tools/objtool/sync-check.sh - -diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h -new file mode 100644 -index 0000000..7dc777a ---- /dev/null -+++ b/arch/x86/include/asm/orc_types.h -@@ -0,0 +1,107 @@ -+/* -+ * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#ifndef _ORC_TYPES_H -+#define _ORC_TYPES_H -+ -+#include <linux/types.h> -+#include <linux/compiler.h> -+ -+/* -+ * The ORC_REG_* registers are base registers which are used to find other -+ * registers on the stack. -+ * -+ * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the -+ * address of the previous frame: the caller's SP before it called the current -+ * function. -+ * -+ * ORC_REG_UNDEFINED means the corresponding register's value didn't change in -+ * the current frame. -+ * -+ * The most commonly used base registers are SP and BP -- which the previous SP -+ * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is -+ * usually based on. -+ * -+ * The rest of the base registers are needed for special cases like entry code -+ * and GCC realigned stacks. -+ */ -+#define ORC_REG_UNDEFINED 0 -+#define ORC_REG_PREV_SP 1 -+#define ORC_REG_DX 2 -+#define ORC_REG_DI 3 -+#define ORC_REG_BP 4 -+#define ORC_REG_SP 5 -+#define ORC_REG_R10 6 -+#define ORC_REG_R13 7 -+#define ORC_REG_BP_INDIRECT 8 -+#define ORC_REG_SP_INDIRECT 9 -+#define ORC_REG_MAX 15 -+ -+/* -+ * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the -+ * caller's SP right before it made the call). Used for all callable -+ * functions, i.e. all C code and all callable asm functions. -+ * -+ * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points -+ * to a fully populated pt_regs from a syscall, interrupt, or exception. -+ * -+ * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset -+ * points to the iret return frame. -+ * -+ * The UNWIND_HINT macros are used only for the unwind_hint struct. They -+ * aren't used in struct orc_entry due to size and complexity constraints. -+ * Objtool converts them to real types when it converts the hints to orc -+ * entries. -+ */ -+#define ORC_TYPE_CALL 0 -+#define ORC_TYPE_REGS 1 -+#define ORC_TYPE_REGS_IRET 2 -+#define UNWIND_HINT_TYPE_SAVE 3 -+#define UNWIND_HINT_TYPE_RESTORE 4 -+ -+#ifndef __ASSEMBLY__ -+/* -+ * This struct is more or less a vastly simplified version of the DWARF Call -+ * Frame Information standard. It contains only the necessary parts of DWARF -+ * CFI, simplified for ease of access by the in-kernel unwinder. It tells the -+ * unwinder how to find the previous SP and BP (and sometimes entry regs) on -+ * the stack for a given code address. Each instance of the struct corresponds -+ * to one or more code locations. -+ */ -+struct orc_entry { -+ s16 sp_offset; -+ s16 bp_offset; -+ unsigned sp_reg:4; -+ unsigned bp_reg:4; -+ unsigned type:2; -+}; -+ -+/* -+ * This struct is used by asm and inline asm code to manually annotate the -+ * location of registers on the stack for the ORC unwinder. -+ * -+ * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. -+ */ -+struct unwind_hint { -+ u32 ip; -+ s16 sp_offset; -+ u8 sp_reg; -+ u8 type; -+}; -+#endif /* __ASSEMBLY__ */ -+ -+#endif /* _ORC_TYPES_H */ -diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h -new file mode 100644 -index 0000000..5e02b11 ---- /dev/null -+++ b/arch/x86/include/asm/unwind_hints.h -@@ -0,0 +1,103 @@ -+#ifndef _ASM_X86_UNWIND_HINTS_H -+#define _ASM_X86_UNWIND_HINTS_H -+ -+#include "orc_types.h" -+ -+#ifdef __ASSEMBLY__ -+ -+/* -+ * In asm, there are two kinds of code: normal C-type callable functions and -+ * the rest. The normal callable functions can be called by other code, and -+ * don't do anything unusual with the stack. Such normal callable functions -+ * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this -+ * category. In this case, no special debugging annotations are needed because -+ * objtool can automatically generate the ORC data for the ORC unwinder to read -+ * at runtime. -+ * -+ * Anything which doesn't fall into the above category, such as syscall and -+ * interrupt handlers, tends to not be called directly by other functions, and -+ * often does unusual non-C-function-type things with the stack pointer. Such -+ * code needs to be annotated such that objtool can understand it. The -+ * following CFI hint macros are for this type of code. -+ * -+ * These macros provide hints to objtool about the state of the stack at each -+ * instruction. Objtool starts from the hints and follows the code flow, -+ * making automatic CFI adjustments when it sees pushes and pops, filling out -+ * the debuginfo as necessary. It will also warn if it sees any -+ * inconsistencies. -+ */ -+.macro UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=0 type=ORC_TYPE_CALL -+#ifdef CONFIG_STACK_VALIDATION -+.Lunwind_hint_ip_\@: -+ .pushsection .discard.unwind_hints -+ /* struct unwind_hint */ -+ .long .Lunwind_hint_ip_\@ - . -+ .short \sp_offset -+ .byte \sp_reg -+ .byte \type -+ .popsection -+#endif -+.endm -+ -+.macro UNWIND_HINT_EMPTY -+ UNWIND_HINT sp_reg=ORC_REG_UNDEFINED -+.endm -+ -+.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 iret=0 -+ .if \base == %rsp && \indirect -+ .set sp_reg, ORC_REG_SP_INDIRECT -+ .elseif \base == %rsp -+ .set sp_reg, ORC_REG_SP -+ .elseif \base == %rbp -+ .set sp_reg, ORC_REG_BP -+ .elseif \base == %rdi -+ .set sp_reg, ORC_REG_DI -+ .elseif \base == %rdx -+ .set sp_reg, ORC_REG_DX -+ .elseif \base == %r10 -+ .set sp_reg, ORC_REG_R10 -+ .else -+ .error "UNWIND_HINT_REGS: bad base register" -+ .endif -+ -+ .set sp_offset, \offset -+ -+ .if \iret -+ .set type, ORC_TYPE_REGS_IRET -+ .elseif \extra == 0 -+ .set type, ORC_TYPE_REGS_IRET -+ .set sp_offset, \offset + (16*8) -+ .else -+ .set type, ORC_TYPE_REGS -+ .endif -+ -+ UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type -+.endm -+ -+.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 -+ UNWIND_HINT_REGS base=\base offset=\offset iret=1 -+.endm -+ -+.macro UNWIND_HINT_FUNC sp_offset=8 -+ UNWIND_HINT sp_offset=\sp_offset -+.endm -+ -+#else /* !__ASSEMBLY__ */ -+ -+#define UNWIND_HINT(sp_reg, sp_offset, type) \ -+ "987: \n\t" \ -+ ".pushsection .discard.unwind_hints\n\t" \ -+ /* struct unwind_hint */ \ -+ ".long 987b - .\n\t" \ -+ ".short " __stringify(sp_offset) "\n\t" \ -+ ".byte " __stringify(sp_reg) "\n\t" \ -+ ".byte " __stringify(type) "\n\t" \ -+ ".popsection\n\t" -+ -+#define UNWIND_HINT_SAVE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_SAVE) -+ -+#define UNWIND_HINT_RESTORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_RESTORE) -+ -+#endif /* __ASSEMBLY__ */ -+ -+#endif /* _ASM_X86_UNWIND_HINTS_H */ -diff --git a/tools/objtool/Build b/tools/objtool/Build -index 6f2e198..749becd 100644 ---- a/tools/objtool/Build -+++ b/tools/objtool/Build -@@ -1,6 +1,9 @@ - objtool-y += arch/$(SRCARCH)/ - objtool-y += builtin-check.o -+objtool-y += builtin-orc.o - objtool-y += check.o -+objtool-y += orc_gen.o -+objtool-y += orc_dump.o - objtool-y += elf.o - objtool-y += special.o - objtool-y += objtool.o -diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt -index 55a60d3..3995735 100644 ---- a/tools/objtool/Documentation/stack-validation.txt -+++ b/tools/objtool/Documentation/stack-validation.txt -@@ -11,9 +11,6 @@ analyzes every .o file and ensures the validity of its stack metadata. - It enforces a set of rules on asm code and C inline assembly code so - that stack traces can be reliable. - --Currently it only checks frame pointer usage, but there are plans to add --CFI validation for C files and CFI generation for asm files. -- - For each function, it recursively follows all possible code paths and - validates the correct frame pointer state at each instruction. - -@@ -23,6 +20,10 @@ alternative execution paths to a given instruction (or set of - instructions). Similarly, it knows how to follow switch statements, for - which gcc sometimes uses jump tables. - -+(Objtool also has an 'orc generate' subcommand which generates debuginfo -+for the ORC unwinder. See Documentation/x86/orc-unwinder.txt in the -+kernel tree for more details.) -+ - - Why do we need stack metadata validation? - ----------------------------------------- -@@ -93,62 +94,24 @@ a) More reliable stack traces for frame pointer enabled kernels - or at the very end of the function after the stack frame has been - destroyed. This is an inherent limitation of frame pointers. - --b) 100% reliable stack traces for DWARF enabled kernels -- -- (NOTE: This is not yet implemented) -- -- As an alternative to frame pointers, DWARF Call Frame Information -- (CFI) metadata can be used to walk the stack. Unlike frame pointers, -- CFI metadata is out of band. So it doesn't affect runtime -- performance and it can be reliable even when interrupts or exceptions -- are involved. -- -- For C code, gcc automatically generates DWARF CFI metadata. But for -- asm code, generating CFI is a tedious manual approach which requires -- manually placed .cfi assembler macros to be scattered throughout the -- code. It's clumsy and very easy to get wrong, and it makes the real -- code harder to read. -- -- Stacktool will improve this situation in several ways. For code -- which already has CFI annotations, it will validate them. For code -- which doesn't have CFI annotations, it will generate them. So an -- architecture can opt to strip out all the manual .cfi annotations -- from their asm code and have objtool generate them instead. -+b) ORC (Oops Rewind Capability) unwind table generation - -- We might also add a runtime stack validation debug option where we -- periodically walk the stack from schedule() and/or an NMI to ensure -- that the stack metadata is sane and that we reach the bottom of the -- stack. -+ An alternative to frame pointers and DWARF, ORC unwind data can be -+ used to walk the stack. Unlike frame pointers, ORC data is out of -+ band. So it doesn't affect runtime performance and it can be -+ reliable even when interrupts or exceptions are involved. - -- So the benefit of objtool here will be that external tooling should -- always show perfect stack traces. And the same will be true for -- kernel warning/oops traces if the architecture has a runtime DWARF -- unwinder. -+ For more details, see Documentation/x86/orc-unwinder.txt. - - c) Higher live patching compatibility rate - -- (NOTE: This is not yet implemented) -- -- Currently with CONFIG_LIVEPATCH there's a basic live patching -- framework which is safe for roughly 85-90% of "security" fixes. But -- patches can't have complex features like function dependency or -- prototype changes, or data structure changes. -- -- There's a strong need to support patches which have the more complex -- features so that the patch compatibility rate for security fixes can -- eventually approach something resembling 100%. To achieve that, a -- "consistency model" is needed, which allows tasks to be safely -- transitioned from an unpatched state to a patched state. -- -- One of the key requirements of the currently proposed livepatch -- consistency model [*] is that it needs to walk the stack of each -- sleeping task to determine if it can be transitioned to the patched -- state. If objtool can ensure that stack traces are reliable, this -- consistency model can be used and the live patching compatibility -- rate can be improved significantly. -- -- [*] https://lkml.kernel.org/r/cover.1423499826.git.jpoimboe@redhat.com -+ Livepatch has an optional "consistency model", which is needed for -+ more complex patches. In order for the consistency model to work, -+ stack traces need to be reliable (or an unreliable condition needs to -+ be detectable). Objtool makes that possible. - -+ For more details, see the livepatch documentation in the Linux kernel -+ source tree at Documentation/livepatch/livepatch.txt. - - Rules - ----- -@@ -201,80 +164,84 @@ To achieve the validation, objtool enforces the following rules: - return normally. - - --Errors in .S files -------------------- -+Objtool warnings -+---------------- -+ -+For asm files, if you're getting an error which doesn't make sense, -+first make sure that the affected code follows the above rules. - --If you're getting an error in a compiled .S file which you don't --understand, first make sure that the affected code follows the above --rules. -+For C files, the common culprits are inline asm statements and calls to -+"noreturn" functions. See below for more details. -+ -+Another possible cause for errors in C code is if the Makefile removes -+-fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. - - Here are some examples of common warnings reported by objtool, what - they mean, and suggestions for how to fix them. - - --1. asm_file.o: warning: objtool: func()+0x128: call without frame pointer save/setup -+1. file.o: warning: objtool: func()+0x128: call without frame pointer save/setup - - The func() function made a function call without first saving and/or -- updating the frame pointer. -- -- If func() is indeed a callable function, add proper frame pointer -- logic using the FRAME_BEGIN and FRAME_END macros. Otherwise, remove -- its ELF function annotation by changing ENDPROC to END. -- -- If you're getting this error in a .c file, see the "Errors in .c -- files" section. -+ updating the frame pointer, and CONFIG_FRAME_POINTER is enabled. - -+ If the error is for an asm file, and func() is indeed a callable -+ function, add proper frame pointer logic using the FRAME_BEGIN and -+ FRAME_END macros. Otherwise, if it's not a callable function, remove -+ its ELF function annotation by changing ENDPROC to END, and instead -+ use the manual unwind hint macros in asm/unwind_hints.h. - --2. asm_file.o: warning: objtool: .text+0x53: return instruction outside of a callable function -+ If it's a GCC-compiled .c file, the error may be because the function -+ uses an inline asm() statement which has a "call" instruction. An -+ asm() statement with a call instruction must declare the use of the -+ stack pointer in its output operand. On x86_64, this means adding -+ the ASM_CALL_CONSTRAINT as an output constraint: - -- A return instruction was detected, but objtool couldn't find a way -- for a callable function to reach the instruction. -+ asm volatile("call func" : ASM_CALL_CONSTRAINT); - -- If the return instruction is inside (or reachable from) a callable -- function, the function needs to be annotated with the ENTRY/ENDPROC -- macros. -+ Otherwise the stack frame may not get created before the call. - -- If you _really_ need a return instruction outside of a function, and -- are 100% sure that it won't affect stack traces, you can tell -- objtool to ignore it. See the "Adding exceptions" section below. - -+2. file.o: warning: objtool: .text+0x53: unreachable instruction - --3. asm_file.o: warning: objtool: func()+0x9: function has unreachable instruction -+ Objtool couldn't find a code path to reach the instruction. - -- The instruction lives inside of a callable function, but there's no -- possible control flow path from the beginning of the function to the -- instruction. -+ If the error is for an asm file, and the instruction is inside (or -+ reachable from) a callable function, the function should be annotated -+ with the ENTRY/ENDPROC macros (ENDPROC is the important one). -+ Otherwise, the code should probably be annotated with the unwind hint -+ macros in asm/unwind_hints.h so objtool and the unwinder can know the -+ stack state associated with the code. - -- If the instruction is actually needed, and it's actually in a -- callable function, ensure that its function is properly annotated -- with ENTRY/ENDPROC. -+ If you're 100% sure the code won't affect stack traces, or if you're -+ a just a bad person, you can tell objtool to ignore it. See the -+ "Adding exceptions" section below. - - If it's not actually in a callable function (e.g. kernel entry code), - change ENDPROC to END. - - --4. asm_file.o: warning: objtool: func(): can't find starting instruction -+4. file.o: warning: objtool: func(): can't find starting instruction - or -- asm_file.o: warning: objtool: func()+0x11dd: can't decode instruction -+ file.o: warning: objtool: func()+0x11dd: can't decode instruction - -- Did you put data in a text section? If so, that can confuse -+ Does the file have data in a text section? If so, that can confuse - objtool's instruction decoder. Move the data to a more appropriate - section like .data or .rodata. - - --5. asm_file.o: warning: objtool: func()+0x6: kernel entry/exit from callable instruction -- -- This is a kernel entry/exit instruction like sysenter or sysret. -- Such instructions aren't allowed in a callable function, and are most -- likely part of the kernel entry code. -+5. file.o: warning: objtool: func()+0x6: unsupported instruction in callable function - -- If the instruction isn't actually in a callable function, change -- ENDPROC to END. -+ This is a kernel entry/exit instruction like sysenter or iret. Such -+ instructions aren't allowed in a callable function, and are most -+ likely part of the kernel entry code. They should usually not have -+ the callable function annotation (ENDPROC) and should always be -+ annotated with the unwind hint macros in asm/unwind_hints.h. - - --6. asm_file.o: warning: objtool: func()+0x26: sibling call from callable instruction with changed frame pointer -+6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame - -- This is a dynamic jump or a jump to an undefined symbol. Stacktool -+ This is a dynamic jump or a jump to an undefined symbol. Objtool - assumed it's a sibling call and detected that the frame pointer - wasn't first restored to its original state. - -@@ -282,24 +249,28 @@ they mean, and suggestions for how to fix them. - destination code to the local file. - - If the instruction is not actually in a callable function (e.g. -- kernel entry code), change ENDPROC to END. -+ kernel entry code), change ENDPROC to END and annotate manually with -+ the unwind hint macros in asm/unwind_hints.h. - - --7. asm_file: warning: objtool: func()+0x5c: frame pointer state mismatch -+7. file: warning: objtool: func()+0x5c: stack state mismatch - - The instruction's frame pointer state is inconsistent, depending on - which execution path was taken to reach the instruction. - -- Make sure the function pushes and sets up the frame pointer (for -- x86_64, this means rbp) at the beginning of the function and pops it -- at the end of the function. Also make sure that no other code in the -- function touches the frame pointer. -+ Make sure that, when CONFIG_FRAME_POINTER is enabled, the function -+ pushes and sets up the frame pointer (for x86_64, this means rbp) at -+ the beginning of the function and pops it at the end of the function. -+ Also make sure that no other code in the function touches the frame -+ pointer. - -+ Another possibility is that the code has some asm or inline asm which -+ does some unusual things to the stack or the frame pointer. In such -+ cases it's probably appropriate to use the unwind hint macros in -+ asm/unwind_hints.h. - --Errors in .c files -------------------- - --1. c_file.o: warning: objtool: funcA() falls through to next function funcB() -+8. file.o: warning: objtool: funcA() falls through to next function funcB() - - This means that funcA() doesn't end with a return instruction or an - unconditional jump, and that objtool has determined that the function -@@ -318,22 +289,6 @@ Errors in .c files - might be corrupt due to a gcc bug. For more details, see: - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 - --2. If you're getting any other objtool error in a compiled .c file, it -- may be because the file uses an asm() statement which has a "call" -- instruction. An asm() statement with a call instruction must declare -- the use of the stack pointer in its output operand. For example, on -- x86_64: -- -- register void *__sp asm("rsp"); -- asm volatile("call func" : "+r" (__sp)); -- -- Otherwise the stack frame may not get created before the call. -- --3. Another possible cause for errors in C code is if the Makefile removes -- -fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. -- --Also see the above section for .S file errors for more information what --the individual error messages mean. - - If the error doesn't seem to make sense, it could be a bug in objtool. - Feel free to ask the objtool maintainer for help. -diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile -index 041b493..e6acc28 100644 ---- a/tools/objtool/Makefile -+++ b/tools/objtool/Makefile -@@ -1,3 +1,4 @@ -+# SPDX-License-Identifier: GPL-2.0 - include ../scripts/Makefile.include - include ../scripts/Makefile.arch - -@@ -6,17 +7,19 @@ ARCH := x86 - endif - - # always use the host compiler --CC = gcc --LD = ld --AR = ar -+HOSTCC ?= gcc -+HOSTLD ?= ld -+CC = $(HOSTCC) -+LD = $(HOSTLD) -+AR = ar - - ifeq ($(srctree),) --srctree := $(patsubst %/,%,$(dir $(shell pwd))) -+srctree := $(patsubst %/,%,$(dir $(CURDIR))) - srctree := $(patsubst %/,%,$(dir $(srctree))) - endif - - SUBCMD_SRCDIR = $(srctree)/tools/lib/subcmd/ --LIBSUBCMD_OUTPUT = $(if $(OUTPUT),$(OUTPUT),$(PWD)/) -+LIBSUBCMD_OUTPUT = $(if $(OUTPUT),$(OUTPUT),$(CURDIR)/) - LIBSUBCMD = $(LIBSUBCMD_OUTPUT)libsubcmd.a - - OBJTOOL := $(OUTPUT)objtool -@@ -24,8 +27,11 @@ OBJTOOL_IN := $(OBJTOOL)-in.o - - all: $(OBJTOOL) - --INCLUDES := -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi --CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) -+INCLUDES := -I$(srctree)/tools/include \ -+ -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \ -+ -I$(srctree)/tools/objtool/arch/$(ARCH)/include -+WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed -+CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) - LDFLAGS += -lelf $(LIBSUBCMD) - - # Allow old libelf to be used: -@@ -39,19 +45,8 @@ include $(srctree)/tools/build/Makefile.include - $(OBJTOOL_IN): fixdep FORCE - @$(MAKE) $(build)=objtool - --# Busybox's diff doesn't have -I, avoid warning in that case --# - $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) -- @(diff -I 2>&1 | grep -q 'option requires an argument' && \ -- test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ -- diff -I'^#include' arch/x86/insn/insn.c ../../arch/x86/lib/insn.c >/dev/null && \ -- diff -I'^#include' arch/x86/insn/inat.c ../../arch/x86/lib/inat.c >/dev/null && \ -- diff arch/x86/insn/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null && \ -- diff arch/x86/insn/gen-insn-attr-x86.awk ../../arch/x86/tools/gen-insn-attr-x86.awk >/dev/null && \ -- diff -I'^#include' arch/x86/insn/insn.h ../../arch/x86/include/asm/insn.h >/dev/null && \ -- diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ -- diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ -- || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true -+ @$(CONFIG_SHELL) ./sync-check.sh - $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ - - -@@ -61,7 +56,7 @@ $(LIBSUBCMD): fixdep FORCE - clean: - $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) - $(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete -- $(Q)$(RM) $(OUTPUT)arch/x86/insn/inat-tables.c $(OUTPUT)fixdep -+ $(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep - - FORCE: - -diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h -index a59e061..b0d7dc3 100644 ---- a/tools/objtool/arch.h -+++ b/tools/objtool/arch.h -@@ -19,25 +19,64 @@ - #define _ARCH_H - - #include <stdbool.h> -+#include <linux/list.h> - #include "elf.h" -+#include "cfi.h" - --#define INSN_FP_SAVE 1 --#define INSN_FP_SETUP 2 --#define INSN_FP_RESTORE 3 --#define INSN_JUMP_CONDITIONAL 4 --#define INSN_JUMP_UNCONDITIONAL 5 --#define INSN_JUMP_DYNAMIC 6 --#define INSN_CALL 7 --#define INSN_CALL_DYNAMIC 8 --#define INSN_RETURN 9 --#define INSN_CONTEXT_SWITCH 10 --#define INSN_NOP 11 --#define INSN_OTHER 12 -+#define INSN_JUMP_CONDITIONAL 1 -+#define INSN_JUMP_UNCONDITIONAL 2 -+#define INSN_JUMP_DYNAMIC 3 -+#define INSN_CALL 4 -+#define INSN_CALL_DYNAMIC 5 -+#define INSN_RETURN 6 -+#define INSN_CONTEXT_SWITCH 7 -+#define INSN_STACK 8 -+#define INSN_BUG 9 -+#define INSN_NOP 10 -+#define INSN_OTHER 11 - #define INSN_LAST INSN_OTHER - -+enum op_dest_type { -+ OP_DEST_REG, -+ OP_DEST_REG_INDIRECT, -+ OP_DEST_MEM, -+ OP_DEST_PUSH, -+ OP_DEST_LEAVE, -+}; -+ -+struct op_dest { -+ enum op_dest_type type; -+ unsigned char reg; -+ int offset; -+}; -+ -+enum op_src_type { -+ OP_SRC_REG, -+ OP_SRC_REG_INDIRECT, -+ OP_SRC_CONST, -+ OP_SRC_POP, -+ OP_SRC_ADD, -+ OP_SRC_AND, -+}; -+ -+struct op_src { -+ enum op_src_type type; -+ unsigned char reg; -+ int offset; -+}; -+ -+struct stack_op { -+ struct op_dest dest; -+ struct op_src src; -+}; -+ -+void arch_initial_func_cfi_state(struct cfi_state *state); -+ - int arch_decode_instruction(struct elf *elf, struct section *sec, - unsigned long offset, unsigned int maxlen, - unsigned int *len, unsigned char *type, -- unsigned long *displacement); -+ unsigned long *immediate, struct stack_op *op); -+ -+bool arch_callee_saved_reg(unsigned char reg); - - #endif /* _ARCH_H */ -diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build -index debbdb0..b998412 100644 ---- a/tools/objtool/arch/x86/Build -+++ b/tools/objtool/arch/x86/Build -@@ -1,12 +1,12 @@ - objtool-y += decode.o - --inat_tables_script = arch/x86/insn/gen-insn-attr-x86.awk --inat_tables_maps = arch/x86/insn/x86-opcode-map.txt -+inat_tables_script = arch/x86/tools/gen-insn-attr-x86.awk -+inat_tables_maps = arch/x86/lib/x86-opcode-map.txt - --$(OUTPUT)arch/x86/insn/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) -+$(OUTPUT)arch/x86/lib/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) - $(call rule_mkdir) - $(Q)$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ - --$(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/insn/inat-tables.c -+$(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/lib/inat-tables.c - --CFLAGS_decode.o += -I$(OUTPUT)arch/x86/insn -+CFLAGS_decode.o += -I$(OUTPUT)arch/x86/lib -diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c -index 9fb487f..006b6d7 100644 ---- a/tools/objtool/arch/x86/decode.c -+++ b/tools/objtool/arch/x86/decode.c -@@ -19,14 +19,25 @@ - #include <stdlib.h> - - #define unlikely(cond) (cond) --#include "insn/insn.h" --#include "insn/inat.c" --#include "insn/insn.c" -+#include <asm/insn.h> -+#include "lib/inat.c" -+#include "lib/insn.c" - - #include "../../elf.h" - #include "../../arch.h" - #include "../../warn.h" - -+static unsigned char op_to_cfi_reg[][2] = { -+ {CFI_AX, CFI_R8}, -+ {CFI_CX, CFI_R9}, -+ {CFI_DX, CFI_R10}, -+ {CFI_BX, CFI_R11}, -+ {CFI_SP, CFI_R12}, -+ {CFI_BP, CFI_R13}, -+ {CFI_SI, CFI_R14}, -+ {CFI_DI, CFI_R15}, -+}; -+ - static int is_x86_64(struct elf *elf) - { - switch (elf->ehdr.e_machine) { -@@ -40,24 +51,50 @@ static int is_x86_64(struct elf *elf) - } - } - -+bool arch_callee_saved_reg(unsigned char reg) -+{ -+ switch (reg) { -+ case CFI_BP: -+ case CFI_BX: -+ case CFI_R12: -+ case CFI_R13: -+ case CFI_R14: -+ case CFI_R15: -+ return true; -+ -+ case CFI_AX: -+ case CFI_CX: -+ case CFI_DX: -+ case CFI_SI: -+ case CFI_DI: -+ case CFI_SP: -+ case CFI_R8: -+ case CFI_R9: -+ case CFI_R10: -+ case CFI_R11: -+ case CFI_RA: -+ default: -+ return false; -+ } -+} -+ - int arch_decode_instruction(struct elf *elf, struct section *sec, - unsigned long offset, unsigned int maxlen, - unsigned int *len, unsigned char *type, -- unsigned long *immediate) -+ unsigned long *immediate, struct stack_op *op) - { - struct insn insn; -- int x86_64; -- unsigned char op1, op2, ext; -+ int x86_64, sign; -+ unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, -+ rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, -+ modrm_reg = 0, sib = 0; - - x86_64 = is_x86_64(elf); - if (x86_64 == -1) - return -1; - -- insn_init(&insn, (void *)(sec->data + offset), maxlen, x86_64); -+ insn_init(&insn, sec->data->d_buf + offset, maxlen, x86_64); - insn_get_length(&insn); -- insn_get_opcode(&insn); -- insn_get_modrm(&insn); -- insn_get_immediate(&insn); - - if (!insn_complete(&insn)) { - WARN_FUNC("can't decode instruction", sec, offset); -@@ -73,67 +110,317 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, - op1 = insn.opcode.bytes[0]; - op2 = insn.opcode.bytes[1]; - -+ if (insn.rex_prefix.nbytes) { -+ rex = insn.rex_prefix.bytes[0]; -+ rex_w = X86_REX_W(rex) >> 3; -+ rex_r = X86_REX_R(rex) >> 2; -+ rex_x = X86_REX_X(rex) >> 1; -+ rex_b = X86_REX_B(rex); -+ } -+ -+ if (insn.modrm.nbytes) { -+ modrm = insn.modrm.bytes[0]; -+ modrm_mod = X86_MODRM_MOD(modrm); -+ modrm_reg = X86_MODRM_REG(modrm); -+ modrm_rm = X86_MODRM_RM(modrm); -+ } -+ -+ if (insn.sib.nbytes) -+ sib = insn.sib.bytes[0]; -+ - switch (op1) { -- case 0x55: -- if (!insn.rex_prefix.nbytes) -- /* push rbp */ -- *type = INSN_FP_SAVE; -+ -+ case 0x1: -+ case 0x29: -+ if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { -+ -+ /* add/sub reg, %rsp */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_ADD; -+ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = CFI_SP; -+ } -+ break; -+ -+ case 0x50 ... 0x57: -+ -+ /* push reg */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_REG; -+ op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; -+ op->dest.type = OP_DEST_PUSH; -+ -+ break; -+ -+ case 0x58 ... 0x5f: -+ -+ /* pop reg */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_POP; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b]; -+ - break; - -- case 0x5d: -- if (!insn.rex_prefix.nbytes) -- /* pop rbp */ -- *type = INSN_FP_RESTORE; -+ case 0x68: -+ case 0x6a: -+ /* push immediate */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_CONST; -+ op->dest.type = OP_DEST_PUSH; - break; - - case 0x70 ... 0x7f: - *type = INSN_JUMP_CONDITIONAL; - break; - -+ case 0x81: -+ case 0x83: -+ if (rex != 0x48) -+ break; -+ -+ if (modrm == 0xe4) { -+ /* and imm, %rsp */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_AND; -+ op->src.reg = CFI_SP; -+ op->src.offset = insn.immediate.value; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = CFI_SP; -+ break; -+ } -+ -+ if (modrm == 0xc4) -+ sign = 1; -+ else if (modrm == 0xec) -+ sign = -1; -+ else -+ break; -+ -+ /* add/sub imm, %rsp */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_ADD; -+ op->src.reg = CFI_SP; -+ op->src.offset = insn.immediate.value * sign; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = CFI_SP; -+ break; -+ - case 0x89: -- if (insn.rex_prefix.nbytes == 1 && -- insn.rex_prefix.bytes[0] == 0x48 && -- insn.modrm.nbytes && insn.modrm.bytes[0] == 0xe5) -- /* mov rsp, rbp */ -- *type = INSN_FP_SETUP; -+ if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) { -+ -+ /* mov %rsp, reg */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_REG; -+ op->src.reg = CFI_SP; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b]; -+ break; -+ } -+ -+ if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { -+ -+ /* mov reg, %rsp */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_REG; -+ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = CFI_SP; -+ break; -+ } -+ -+ /* fallthrough */ -+ case 0x88: -+ if (!rex_b && -+ (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) { -+ -+ /* mov reg, disp(%rbp) */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_REG; -+ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; -+ op->dest.type = OP_DEST_REG_INDIRECT; -+ op->dest.reg = CFI_BP; -+ op->dest.offset = insn.displacement.value; -+ -+ } else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) { -+ -+ /* mov reg, disp(%rsp) */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_REG; -+ op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; -+ op->dest.type = OP_DEST_REG_INDIRECT; -+ op->dest.reg = CFI_SP; -+ op->dest.offset = insn.displacement.value; -+ } -+ -+ break; -+ -+ case 0x8b: -+ if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) { -+ -+ /* mov disp(%rbp), reg */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_REG_INDIRECT; -+ op->src.reg = CFI_BP; -+ op->src.offset = insn.displacement.value; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; -+ -+ } else if (rex_w && !rex_b && sib == 0x24 && -+ modrm_mod != 3 && modrm_rm == 4) { -+ -+ /* mov disp(%rsp), reg */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_REG_INDIRECT; -+ op->src.reg = CFI_SP; -+ op->src.offset = insn.displacement.value; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; -+ } -+ - break; - - case 0x8d: -- if (insn.rex_prefix.nbytes && -- insn.rex_prefix.bytes[0] == 0x48 && -- insn.modrm.nbytes && insn.modrm.bytes[0] == 0x2c && -- insn.sib.nbytes && insn.sib.bytes[0] == 0x24) -- /* lea %(rsp), %rbp */ -- *type = INSN_FP_SETUP; -+ if (sib == 0x24 && rex_w && !rex_b && !rex_x) { -+ -+ *type = INSN_STACK; -+ if (!insn.displacement.value) { -+ /* lea (%rsp), reg */ -+ op->src.type = OP_SRC_REG; -+ } else { -+ /* lea disp(%rsp), reg */ -+ op->src.type = OP_SRC_ADD; -+ op->src.offset = insn.displacement.value; -+ } -+ op->src.reg = CFI_SP; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; -+ -+ } else if (rex == 0x48 && modrm == 0x65) { -+ -+ /* lea disp(%rbp), %rsp */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_ADD; -+ op->src.reg = CFI_BP; -+ op->src.offset = insn.displacement.value; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = CFI_SP; -+ -+ } else if (rex == 0x49 && modrm == 0x62 && -+ insn.displacement.value == -8) { -+ -+ /* -+ * lea -0x8(%r10), %rsp -+ * -+ * Restoring rsp back to its original value after a -+ * stack realignment. -+ */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_ADD; -+ op->src.reg = CFI_R10; -+ op->src.offset = -8; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = CFI_SP; -+ -+ } else if (rex == 0x49 && modrm == 0x65 && -+ insn.displacement.value == -16) { -+ -+ /* -+ * lea -0x10(%r13), %rsp -+ * -+ * Restoring rsp back to its original value after a -+ * stack realignment. -+ */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_ADD; -+ op->src.reg = CFI_R13; -+ op->src.offset = -16; -+ op->dest.type = OP_DEST_REG; -+ op->dest.reg = CFI_SP; -+ } -+ -+ break; -+ -+ case 0x8f: -+ /* pop to mem */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_POP; -+ op->dest.type = OP_DEST_MEM; - break; - - case 0x90: - *type = INSN_NOP; - break; - -+ case 0x9c: -+ /* pushf */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_CONST; -+ op->dest.type = OP_DEST_PUSH; -+ break; -+ -+ case 0x9d: -+ /* popf */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_POP; -+ op->dest.type = OP_DEST_MEM; -+ break; -+ - case 0x0f: -- if (op2 >= 0x80 && op2 <= 0x8f) -+ -+ if (op2 >= 0x80 && op2 <= 0x8f) { -+ - *type = INSN_JUMP_CONDITIONAL; -- else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || -- op2 == 0x35) -+ -+ } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || -+ op2 == 0x35) { -+ - /* sysenter, sysret */ - *type = INSN_CONTEXT_SWITCH; -- else if (op2 == 0x0d || op2 == 0x1f) -+ -+ } else if (op2 == 0x0b || op2 == 0xb9) { -+ -+ /* ud2 */ -+ *type = INSN_BUG; -+ -+ } else if (op2 == 0x0d || op2 == 0x1f) { -+ - /* nopl/nopw */ - *type = INSN_NOP; -- else if (op2 == 0x01 && insn.modrm.nbytes && -- (insn.modrm.bytes[0] == 0xc2 || -- insn.modrm.bytes[0] == 0xd8)) -- /* vmlaunch, vmrun */ -- *type = INSN_CONTEXT_SWITCH; -+ -+ } else if (op2 == 0xa0 || op2 == 0xa8) { -+ -+ /* push fs/gs */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_CONST; -+ op->dest.type = OP_DEST_PUSH; -+ -+ } else if (op2 == 0xa1 || op2 == 0xa9) { -+ -+ /* pop fs/gs */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_POP; -+ op->dest.type = OP_DEST_MEM; -+ } - - break; - -- case 0xc9: /* leave */ -- *type = INSN_FP_RESTORE; -+ case 0xc9: -+ /* -+ * leave -+ * -+ * equivalent to: -+ * mov bp, sp -+ * pop bp -+ */ -+ *type = INSN_STACK; -+ op->dest.type = OP_DEST_LEAVE; -+ - break; - -- case 0xe3: /* jecxz/jrcxz */ -+ case 0xe3: -+ /* jecxz/jrcxz */ - *type = INSN_JUMP_CONDITIONAL; - break; - -@@ -158,14 +445,27 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, - break; - - case 0xff: -- ext = X86_MODRM_REG(insn.modrm.bytes[0]); -- if (ext == 2 || ext == 3) -+ if (modrm_reg == 2 || modrm_reg == 3) -+ - *type = INSN_CALL_DYNAMIC; -- else if (ext == 4) -+ -+ else if (modrm_reg == 4) -+ - *type = INSN_JUMP_DYNAMIC; -- else if (ext == 5) /*jmpf */ -+ -+ else if (modrm_reg == 5) -+ -+ /* jmpf */ - *type = INSN_CONTEXT_SWITCH; - -+ else if (modrm_reg == 6) { -+ -+ /* push from mem */ -+ *type = INSN_STACK; -+ op->src.type = OP_SRC_CONST; -+ op->dest.type = OP_DEST_PUSH; -+ } -+ - break; - - default: -@@ -176,3 +476,21 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, - - return 0; - } -+ -+void arch_initial_func_cfi_state(struct cfi_state *state) -+{ -+ int i; -+ -+ for (i = 0; i < CFI_NUM_REGS; i++) { -+ state->regs[i].base = CFI_UNDEFINED; -+ state->regs[i].offset = 0; -+ } -+ -+ /* initial CFA (call frame address) */ -+ state->cfa.base = CFI_SP; -+ state->cfa.offset = 8; -+ -+ /* initial RA (return address) */ -+ state->regs[16].base = CFI_CFA; -+ state->regs[16].offset = -8; -+} -diff --git a/tools/objtool/arch/x86/include/asm/inat.h b/tools/objtool/arch/x86/include/asm/inat.h -new file mode 100644 -index 0000000..1c78580 ---- /dev/null -+++ b/tools/objtool/arch/x86/include/asm/inat.h -@@ -0,0 +1,244 @@ -+#ifndef _ASM_X86_INAT_H -+#define _ASM_X86_INAT_H -+/* -+ * x86 instruction attributes -+ * -+ * Written by Masami Hiramatsu <mhiramat@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ */ -+#include <asm/inat_types.h> -+ -+/* -+ * Internal bits. Don't use bitmasks directly, because these bits are -+ * unstable. You should use checking functions. -+ */ -+ -+#define INAT_OPCODE_TABLE_SIZE 256 -+#define INAT_GROUP_TABLE_SIZE 8 -+ -+/* Legacy last prefixes */ -+#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ -+#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ -+#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ -+/* Other Legacy prefixes */ -+#define INAT_PFX_LOCK 4 /* 0xF0 */ -+#define INAT_PFX_CS 5 /* 0x2E */ -+#define INAT_PFX_DS 6 /* 0x3E */ -+#define INAT_PFX_ES 7 /* 0x26 */ -+#define INAT_PFX_FS 8 /* 0x64 */ -+#define INAT_PFX_GS 9 /* 0x65 */ -+#define INAT_PFX_SS 10 /* 0x36 */ -+#define INAT_PFX_ADDRSZ 11 /* 0x67 */ -+/* x86-64 REX prefix */ -+#define INAT_PFX_REX 12 /* 0x4X */ -+/* AVX VEX prefixes */ -+#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ -+#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ -+#define INAT_PFX_EVEX 15 /* EVEX prefix */ -+ -+#define INAT_LSTPFX_MAX 3 -+#define INAT_LGCPFX_MAX 11 -+ -+/* Immediate size */ -+#define INAT_IMM_BYTE 1 -+#define INAT_IMM_WORD 2 -+#define INAT_IMM_DWORD 3 -+#define INAT_IMM_QWORD 4 -+#define INAT_IMM_PTR 5 -+#define INAT_IMM_VWORD32 6 -+#define INAT_IMM_VWORD 7 -+ -+/* Legacy prefix */ -+#define INAT_PFX_OFFS 0 -+#define INAT_PFX_BITS 4 -+#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) -+#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) -+/* Escape opcodes */ -+#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) -+#define INAT_ESC_BITS 2 -+#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) -+#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) -+/* Group opcodes (1-16) */ -+#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) -+#define INAT_GRP_BITS 5 -+#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) -+#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) -+/* Immediates */ -+#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) -+#define INAT_IMM_BITS 3 -+#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) -+/* Flags */ -+#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) -+#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) -+#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) -+#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) -+#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) -+#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) -+#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) -+#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) -+#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) -+/* Attribute making macros for attribute tables */ -+#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) -+#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) -+#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) -+#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) -+ -+/* Identifiers for segment registers */ -+#define INAT_SEG_REG_IGNORE 0 -+#define INAT_SEG_REG_DEFAULT 1 -+#define INAT_SEG_REG_CS 2 -+#define INAT_SEG_REG_SS 3 -+#define INAT_SEG_REG_DS 4 -+#define INAT_SEG_REG_ES 5 -+#define INAT_SEG_REG_FS 6 -+#define INAT_SEG_REG_GS 7 -+ -+/* Attribute search APIs */ -+extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); -+extern int inat_get_last_prefix_id(insn_byte_t last_pfx); -+extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, -+ int lpfx_id, -+ insn_attr_t esc_attr); -+extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, -+ int lpfx_id, -+ insn_attr_t esc_attr); -+extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, -+ insn_byte_t vex_m, -+ insn_byte_t vex_pp); -+ -+/* Attribute checking functions */ -+static inline int inat_is_legacy_prefix(insn_attr_t attr) -+{ -+ attr &= INAT_PFX_MASK; -+ return attr && attr <= INAT_LGCPFX_MAX; -+} -+ -+static inline int inat_is_address_size_prefix(insn_attr_t attr) -+{ -+ return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; -+} -+ -+static inline int inat_is_operand_size_prefix(insn_attr_t attr) -+{ -+ return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; -+} -+ -+static inline int inat_is_rex_prefix(insn_attr_t attr) -+{ -+ return (attr & INAT_PFX_MASK) == INAT_PFX_REX; -+} -+ -+static inline int inat_last_prefix_id(insn_attr_t attr) -+{ -+ if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) -+ return 0; -+ else -+ return attr & INAT_PFX_MASK; -+} -+ -+static inline int inat_is_vex_prefix(insn_attr_t attr) -+{ -+ attr &= INAT_PFX_MASK; -+ return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || -+ attr == INAT_PFX_EVEX; -+} -+ -+static inline int inat_is_evex_prefix(insn_attr_t attr) -+{ -+ return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; -+} -+ -+static inline int inat_is_vex3_prefix(insn_attr_t attr) -+{ -+ return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; -+} -+ -+static inline int inat_is_escape(insn_attr_t attr) -+{ -+ return attr & INAT_ESC_MASK; -+} -+ -+static inline int inat_escape_id(insn_attr_t attr) -+{ -+ return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; -+} -+ -+static inline int inat_is_group(insn_attr_t attr) -+{ -+ return attr & INAT_GRP_MASK; -+} -+ -+static inline int inat_group_id(insn_attr_t attr) -+{ -+ return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; -+} -+ -+static inline int inat_group_common_attribute(insn_attr_t attr) -+{ -+ return attr & ~INAT_GRP_MASK; -+} -+ -+static inline int inat_has_immediate(insn_attr_t attr) -+{ -+ return attr & INAT_IMM_MASK; -+} -+ -+static inline int inat_immediate_size(insn_attr_t attr) -+{ -+ return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; -+} -+ -+static inline int inat_has_modrm(insn_attr_t attr) -+{ -+ return attr & INAT_MODRM; -+} -+ -+static inline int inat_is_force64(insn_attr_t attr) -+{ -+ return attr & INAT_FORCE64; -+} -+ -+static inline int inat_has_second_immediate(insn_attr_t attr) -+{ -+ return attr & INAT_SCNDIMM; -+} -+ -+static inline int inat_has_moffset(insn_attr_t attr) -+{ -+ return attr & INAT_MOFFSET; -+} -+ -+static inline int inat_has_variant(insn_attr_t attr) -+{ -+ return attr & INAT_VARIANT; -+} -+ -+static inline int inat_accept_vex(insn_attr_t attr) -+{ -+ return attr & INAT_VEXOK; -+} -+ -+static inline int inat_must_vex(insn_attr_t attr) -+{ -+ return attr & (INAT_VEXONLY | INAT_EVEXONLY); -+} -+ -+static inline int inat_must_evex(insn_attr_t attr) -+{ -+ return attr & INAT_EVEXONLY; -+} -+#endif -diff --git a/tools/objtool/arch/x86/include/asm/inat_types.h b/tools/objtool/arch/x86/include/asm/inat_types.h -new file mode 100644 -index 0000000..cb3c20c ---- /dev/null -+++ b/tools/objtool/arch/x86/include/asm/inat_types.h -@@ -0,0 +1,29 @@ -+#ifndef _ASM_X86_INAT_TYPES_H -+#define _ASM_X86_INAT_TYPES_H -+/* -+ * x86 instruction attributes -+ * -+ * Written by Masami Hiramatsu <mhiramat@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ */ -+ -+/* Instruction attributes */ -+typedef unsigned int insn_attr_t; -+typedef unsigned char insn_byte_t; -+typedef signed int insn_value_t; -+ -+#endif -diff --git a/tools/objtool/arch/x86/include/asm/insn.h b/tools/objtool/arch/x86/include/asm/insn.h -new file mode 100644 -index 0000000..b3e32b0 ---- /dev/null -+++ b/tools/objtool/arch/x86/include/asm/insn.h -@@ -0,0 +1,211 @@ -+#ifndef _ASM_X86_INSN_H -+#define _ASM_X86_INSN_H -+/* -+ * x86 instruction analysis -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) IBM Corporation, 2009 -+ */ -+ -+/* insn_attr_t is defined in inat.h */ -+#include <asm/inat.h> -+ -+struct insn_field { -+ union { -+ insn_value_t value; -+ insn_byte_t bytes[4]; -+ }; -+ /* !0 if we've run insn_get_xxx() for this field */ -+ unsigned char got; -+ unsigned char nbytes; -+}; -+ -+struct insn { -+ struct insn_field prefixes; /* -+ * Prefixes -+ * prefixes.bytes[3]: last prefix -+ */ -+ struct insn_field rex_prefix; /* REX prefix */ -+ struct insn_field vex_prefix; /* VEX prefix */ -+ struct insn_field opcode; /* -+ * opcode.bytes[0]: opcode1 -+ * opcode.bytes[1]: opcode2 -+ * opcode.bytes[2]: opcode3 -+ */ -+ struct insn_field modrm; -+ struct insn_field sib; -+ struct insn_field displacement; -+ union { -+ struct insn_field immediate; -+ struct insn_field moffset1; /* for 64bit MOV */ -+ struct insn_field immediate1; /* for 64bit imm or off16/32 */ -+ }; -+ union { -+ struct insn_field moffset2; /* for 64bit MOV */ -+ struct insn_field immediate2; /* for 64bit imm or seg16 */ -+ }; -+ -+ insn_attr_t attr; -+ unsigned char opnd_bytes; -+ unsigned char addr_bytes; -+ unsigned char length; -+ unsigned char x86_64; -+ -+ const insn_byte_t *kaddr; /* kernel address of insn to analyze */ -+ const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ -+ const insn_byte_t *next_byte; -+}; -+ -+#define MAX_INSN_SIZE 15 -+ -+#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) -+#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) -+#define X86_MODRM_RM(modrm) ((modrm) & 0x07) -+ -+#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) -+#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) -+#define X86_SIB_BASE(sib) ((sib) & 0x07) -+ -+#define X86_REX_W(rex) ((rex) & 8) -+#define X86_REX_R(rex) ((rex) & 4) -+#define X86_REX_X(rex) ((rex) & 2) -+#define X86_REX_B(rex) ((rex) & 1) -+ -+/* VEX bit flags */ -+#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ -+#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ -+#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ -+#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ -+#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ -+/* VEX bit fields */ -+#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ -+#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ -+#define X86_VEX2_M 1 /* VEX2.M always 1 */ -+#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ -+#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ -+#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ -+ -+extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); -+extern void insn_get_prefixes(struct insn *insn); -+extern void insn_get_opcode(struct insn *insn); -+extern void insn_get_modrm(struct insn *insn); -+extern void insn_get_sib(struct insn *insn); -+extern void insn_get_displacement(struct insn *insn); -+extern void insn_get_immediate(struct insn *insn); -+extern void insn_get_length(struct insn *insn); -+ -+/* Attribute will be determined after getting ModRM (for opcode groups) */ -+static inline void insn_get_attribute(struct insn *insn) -+{ -+ insn_get_modrm(insn); -+} -+ -+/* Instruction uses RIP-relative addressing */ -+extern int insn_rip_relative(struct insn *insn); -+ -+/* Init insn for kernel text */ -+static inline void kernel_insn_init(struct insn *insn, -+ const void *kaddr, int buf_len) -+{ -+#ifdef CONFIG_X86_64 -+ insn_init(insn, kaddr, buf_len, 1); -+#else /* CONFIG_X86_32 */ -+ insn_init(insn, kaddr, buf_len, 0); -+#endif -+} -+ -+static inline int insn_is_avx(struct insn *insn) -+{ -+ if (!insn->prefixes.got) -+ insn_get_prefixes(insn); -+ return (insn->vex_prefix.value != 0); -+} -+ -+static inline int insn_is_evex(struct insn *insn) -+{ -+ if (!insn->prefixes.got) -+ insn_get_prefixes(insn); -+ return (insn->vex_prefix.nbytes == 4); -+} -+ -+/* Ensure this instruction is decoded completely */ -+static inline int insn_complete(struct insn *insn) -+{ -+ return insn->opcode.got && insn->modrm.got && insn->sib.got && -+ insn->displacement.got && insn->immediate.got; -+} -+ -+static inline insn_byte_t insn_vex_m_bits(struct insn *insn) -+{ -+ if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ -+ return X86_VEX2_M; -+ else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ -+ return X86_VEX3_M(insn->vex_prefix.bytes[1]); -+ else /* EVEX */ -+ return X86_EVEX_M(insn->vex_prefix.bytes[1]); -+} -+ -+static inline insn_byte_t insn_vex_p_bits(struct insn *insn) -+{ -+ if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ -+ return X86_VEX_P(insn->vex_prefix.bytes[1]); -+ else -+ return X86_VEX_P(insn->vex_prefix.bytes[2]); -+} -+ -+/* Get the last prefix id from last prefix or VEX prefix */ -+static inline int insn_last_prefix_id(struct insn *insn) -+{ -+ if (insn_is_avx(insn)) -+ return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ -+ -+ if (insn->prefixes.bytes[3]) -+ return inat_get_last_prefix_id(insn->prefixes.bytes[3]); -+ -+ return 0; -+} -+ -+/* Offset of each field from kaddr */ -+static inline int insn_offset_rex_prefix(struct insn *insn) -+{ -+ return insn->prefixes.nbytes; -+} -+static inline int insn_offset_vex_prefix(struct insn *insn) -+{ -+ return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; -+} -+static inline int insn_offset_opcode(struct insn *insn) -+{ -+ return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; -+} -+static inline int insn_offset_modrm(struct insn *insn) -+{ -+ return insn_offset_opcode(insn) + insn->opcode.nbytes; -+} -+static inline int insn_offset_sib(struct insn *insn) -+{ -+ return insn_offset_modrm(insn) + insn->modrm.nbytes; -+} -+static inline int insn_offset_displacement(struct insn *insn) -+{ -+ return insn_offset_sib(insn) + insn->sib.nbytes; -+} -+static inline int insn_offset_immediate(struct insn *insn) -+{ -+ return insn_offset_displacement(insn) + insn->displacement.nbytes; -+} -+ -+#endif /* _ASM_X86_INSN_H */ -diff --git a/tools/objtool/arch/x86/include/asm/orc_types.h b/tools/objtool/arch/x86/include/asm/orc_types.h -new file mode 100644 -index 0000000..9c9dc57 ---- /dev/null -+++ b/tools/objtool/arch/x86/include/asm/orc_types.h -@@ -0,0 +1,107 @@ -+/* -+ * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#ifndef _ORC_TYPES_H -+#define _ORC_TYPES_H -+ -+#include <linux/types.h> -+#include <linux/compiler.h> -+ -+/* -+ * The ORC_REG_* registers are base registers which are used to find other -+ * registers on the stack. -+ * -+ * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the -+ * address of the previous frame: the caller's SP before it called the current -+ * function. -+ * -+ * ORC_REG_UNDEFINED means the corresponding register's value didn't change in -+ * the current frame. -+ * -+ * The most commonly used base registers are SP and BP -- which the previous SP -+ * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is -+ * usually based on. -+ * -+ * The rest of the base registers are needed for special cases like entry code -+ * and GCC realigned stacks. -+ */ -+#define ORC_REG_UNDEFINED 0 -+#define ORC_REG_PREV_SP 1 -+#define ORC_REG_DX 2 -+#define ORC_REG_DI 3 -+#define ORC_REG_BP 4 -+#define ORC_REG_SP 5 -+#define ORC_REG_R10 6 -+#define ORC_REG_R13 7 -+#define ORC_REG_BP_INDIRECT 8 -+#define ORC_REG_SP_INDIRECT 9 -+#define ORC_REG_MAX 15 -+ -+/* -+ * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the -+ * caller's SP right before it made the call). Used for all callable -+ * functions, i.e. all C code and all callable asm functions. -+ * -+ * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points -+ * to a fully populated pt_regs from a syscall, interrupt, or exception. -+ * -+ * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset -+ * points to the iret return frame. -+ * -+ * The UNWIND_HINT macros are used only for the unwind_hint struct. They -+ * aren't used in struct orc_entry due to size and complexity constraints. -+ * Objtool converts them to real types when it converts the hints to orc -+ * entries. -+ */ -+#define ORC_TYPE_CALL 0 -+#define ORC_TYPE_REGS 1 -+#define ORC_TYPE_REGS_IRET 2 -+#define UNWIND_HINT_TYPE_SAVE 3 -+#define UNWIND_HINT_TYPE_RESTORE 4 -+ -+#ifndef __ASSEMBLY__ -+/* -+ * This struct is more or less a vastly simplified version of the DWARF Call -+ * Frame Information standard. It contains only the necessary parts of DWARF -+ * CFI, simplified for ease of access by the in-kernel unwinder. It tells the -+ * unwinder how to find the previous SP and BP (and sometimes entry regs) on -+ * the stack for a given code address. Each instance of the struct corresponds -+ * to one or more code locations. -+ */ -+struct orc_entry { -+ s16 sp_offset; -+ s16 bp_offset; -+ unsigned sp_reg:4; -+ unsigned bp_reg:4; -+ unsigned type:2; -+} __packed; -+ -+/* -+ * This struct is used by asm and inline asm code to manually annotate the -+ * location of registers on the stack for the ORC unwinder. -+ * -+ * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. -+ */ -+struct unwind_hint { -+ u32 ip; -+ s16 sp_offset; -+ u8 sp_reg; -+ u8 type; -+}; -+#endif /* __ASSEMBLY__ */ -+ -+#endif /* _ORC_TYPES_H */ -diff --git a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk b/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk -deleted file mode 100644 -index a3d2c62..0000000 ---- a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk -+++ /dev/null -@@ -1,392 +0,0 @@ --#!/bin/awk -f --# gen-insn-attr-x86.awk: Instruction attribute table generator --# Written by Masami Hiramatsu <mhiramat@redhat.com> --# --# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c -- --# Awk implementation sanity check --function check_awk_implement() { -- if (sprintf("%x", 0) != "0") -- return "Your awk has a printf-format problem." -- return "" --} -- --# Clear working vars --function clear_vars() { -- delete table -- delete lptable2 -- delete lptable1 -- delete lptable3 -- eid = -1 # escape id -- gid = -1 # group id -- aid = -1 # AVX id -- tname = "" --} -- --BEGIN { -- # Implementation error checking -- awkchecked = check_awk_implement() -- if (awkchecked != "") { -- print "Error: " awkchecked > "/dev/stderr" -- print "Please try to use gawk." > "/dev/stderr" -- exit 1 -- } -- -- # Setup generating tables -- print "/* x86 opcode map generated from x86-opcode-map.txt */" -- print "/* Do not change this code. */\n" -- ggid = 1 -- geid = 1 -- gaid = 0 -- delete etable -- delete gtable -- delete atable -- -- opnd_expr = "^[A-Za-z/]" -- ext_expr = "^\\(" -- sep_expr = "^\\|$" -- group_expr = "^Grp[0-9A-Za-z]+" -- -- imm_expr = "^[IJAOL][a-z]" -- imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" -- imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" -- imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" -- imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" -- imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" -- imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" -- imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" -- imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" -- imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" -- imm_flag["Ob"] = "INAT_MOFFSET" -- imm_flag["Ov"] = "INAT_MOFFSET" -- imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" -- -- modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" -- force64_expr = "\\([df]64\\)" -- rex_expr = "^REX(\\.[XRWB]+)*" -- fpu_expr = "^ESC" # TODO -- -- lprefix1_expr = "\\((66|!F3)\\)" -- lprefix2_expr = "\\(F3\\)" -- lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)" -- lprefix_expr = "\\((66|F2|F3)\\)" -- max_lprefix = 4 -- -- # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript -- # accepts VEX prefix -- vexok_opcode_expr = "^[vk].*" -- vexok_expr = "\\(v1\\)" -- # All opcodes with (v) superscript supports *only* VEX prefix -- vexonly_expr = "\\(v\\)" -- # All opcodes with (ev) superscript supports *only* EVEX prefix -- evexonly_expr = "\\(ev\\)" -- -- prefix_expr = "\\(Prefix\\)" -- prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" -- prefix_num["REPNE"] = "INAT_PFX_REPNE" -- prefix_num["REP/REPE"] = "INAT_PFX_REPE" -- prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" -- prefix_num["XRELEASE"] = "INAT_PFX_REPE" -- prefix_num["LOCK"] = "INAT_PFX_LOCK" -- prefix_num["SEG=CS"] = "INAT_PFX_CS" -- prefix_num["SEG=DS"] = "INAT_PFX_DS" -- prefix_num["SEG=ES"] = "INAT_PFX_ES" -- prefix_num["SEG=FS"] = "INAT_PFX_FS" -- prefix_num["SEG=GS"] = "INAT_PFX_GS" -- prefix_num["SEG=SS"] = "INAT_PFX_SS" -- prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" -- prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" -- prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" -- prefix_num["EVEX"] = "INAT_PFX_EVEX" -- -- clear_vars() --} -- --function semantic_error(msg) { -- print "Semantic error at " NR ": " msg > "/dev/stderr" -- exit 1 --} -- --function debug(msg) { -- print "DEBUG: " msg --} -- --function array_size(arr, i,c) { -- c = 0 -- for (i in arr) -- c++ -- return c --} -- --/^Table:/ { -- print "/* " $0 " */" -- if (tname != "") -- semantic_error("Hit Table: before EndTable:."); --} -- --/^Referrer:/ { -- if (NF != 1) { -- # escape opcode table -- ref = "" -- for (i = 2; i <= NF; i++) -- ref = ref $i -- eid = escape[ref] -- tname = sprintf("inat_escape_table_%d", eid) -- } --} -- --/^AVXcode:/ { -- if (NF != 1) { -- # AVX/escape opcode table -- aid = $2 -- if (gaid <= aid) -- gaid = aid + 1 -- if (tname == "") # AVX only opcode table -- tname = sprintf("inat_avx_table_%d", $2) -- } -- if (aid == -1 && eid == -1) # primary opcode table -- tname = "inat_primary_table" --} -- --/^GrpTable:/ { -- print "/* " $0 " */" -- if (!($2 in group)) -- semantic_error("No group: " $2 ) -- gid = group[$2] -- tname = "inat_group_table_" gid --} -- --function print_table(tbl,name,fmt,n) --{ -- print "const insn_attr_t " name " = {" -- for (i = 0; i < n; i++) { -- id = sprintf(fmt, i) -- if (tbl[id]) -- print " [" id "] = " tbl[id] "," -- } -- print "};" --} -- --/^EndTable/ { -- if (gid != -1) { -- # print group tables -- if (array_size(table) != 0) { -- print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", -- "0x%x", 8) -- gtable[gid,0] = tname -- } -- if (array_size(lptable1) != 0) { -- print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", -- "0x%x", 8) -- gtable[gid,1] = tname "_1" -- } -- if (array_size(lptable2) != 0) { -- print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", -- "0x%x", 8) -- gtable[gid,2] = tname "_2" -- } -- if (array_size(lptable3) != 0) { -- print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", -- "0x%x", 8) -- gtable[gid,3] = tname "_3" -- } -- } else { -- # print primary/escaped tables -- if (array_size(table) != 0) { -- print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", -- "0x%02x", 256) -- etable[eid,0] = tname -- if (aid >= 0) -- atable[aid,0] = tname -- } -- if (array_size(lptable1) != 0) { -- print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", -- "0x%02x", 256) -- etable[eid,1] = tname "_1" -- if (aid >= 0) -- atable[aid,1] = tname "_1" -- } -- if (array_size(lptable2) != 0) { -- print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", -- "0x%02x", 256) -- etable[eid,2] = tname "_2" -- if (aid >= 0) -- atable[aid,2] = tname "_2" -- } -- if (array_size(lptable3) != 0) { -- print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", -- "0x%02x", 256) -- etable[eid,3] = tname "_3" -- if (aid >= 0) -- atable[aid,3] = tname "_3" -- } -- } -- print "" -- clear_vars() --} -- --function add_flags(old,new) { -- if (old && new) -- return old " | " new -- else if (old) -- return old -- else -- return new --} -- --# convert operands to flags. --function convert_operands(count,opnd, i,j,imm,mod) --{ -- imm = null -- mod = null -- for (j = 1; j <= count; j++) { -- i = opnd[j] -- if (match(i, imm_expr) == 1) { -- if (!imm_flag[i]) -- semantic_error("Unknown imm opnd: " i) -- if (imm) { -- if (i != "Ib") -- semantic_error("Second IMM error") -- imm = add_flags(imm, "INAT_SCNDIMM") -- } else -- imm = imm_flag[i] -- } else if (match(i, modrm_expr)) -- mod = "INAT_MODRM" -- } -- return add_flags(imm, mod) --} -- --/^[0-9a-f]+\:/ { -- if (NR == 1) -- next -- # get index -- idx = "0x" substr($1, 1, index($1,":") - 1) -- if (idx in table) -- semantic_error("Redefine " idx " in " tname) -- -- # check if escaped opcode -- if ("escape" == $2) { -- if ($3 != "#") -- semantic_error("No escaped name") -- ref = "" -- for (i = 4; i <= NF; i++) -- ref = ref $i -- if (ref in escape) -- semantic_error("Redefine escape (" ref ")") -- escape[ref] = geid -- geid++ -- table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" -- next -- } -- -- variant = null -- # converts -- i = 2 -- while (i <= NF) { -- opcode = $(i++) -- delete opnds -- ext = null -- flags = null -- opnd = null -- # parse one opcode -- if (match($i, opnd_expr)) { -- opnd = $i -- count = split($(i++), opnds, ",") -- flags = convert_operands(count, opnds) -- } -- if (match($i, ext_expr)) -- ext = $(i++) -- if (match($i, sep_expr)) -- i++ -- else if (i < NF) -- semantic_error($i " is not a separator") -- -- # check if group opcode -- if (match(opcode, group_expr)) { -- if (!(opcode in group)) { -- group[opcode] = ggid -- ggid++ -- } -- flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") -- } -- # check force(or default) 64bit -- if (match(ext, force64_expr)) -- flags = add_flags(flags, "INAT_FORCE64") -- -- # check REX prefix -- if (match(opcode, rex_expr)) -- flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") -- -- # check coprocessor escape : TODO -- if (match(opcode, fpu_expr)) -- flags = add_flags(flags, "INAT_MODRM") -- -- # check VEX codes -- if (match(ext, evexonly_expr)) -- flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") -- else if (match(ext, vexonly_expr)) -- flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") -- else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) -- flags = add_flags(flags, "INAT_VEXOK") -- -- # check prefixes -- if (match(ext, prefix_expr)) { -- if (!prefix_num[opcode]) -- semantic_error("Unknown prefix: " opcode) -- flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") -- } -- if (length(flags) == 0) -- continue -- # check if last prefix -- if (match(ext, lprefix1_expr)) { -- lptable1[idx] = add_flags(lptable1[idx],flags) -- variant = "INAT_VARIANT" -- } -- if (match(ext, lprefix2_expr)) { -- lptable2[idx] = add_flags(lptable2[idx],flags) -- variant = "INAT_VARIANT" -- } -- if (match(ext, lprefix3_expr)) { -- lptable3[idx] = add_flags(lptable3[idx],flags) -- variant = "INAT_VARIANT" -- } -- if (!match(ext, lprefix_expr)){ -- table[idx] = add_flags(table[idx],flags) -- } -- } -- if (variant) -- table[idx] = add_flags(table[idx],variant) --} -- --END { -- if (awkchecked != "") -- exit 1 -- # print escape opcode map's array -- print "/* Escape opcode map array */" -- print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ -- "[INAT_LSTPFX_MAX + 1] = {" -- for (i = 0; i < geid; i++) -- for (j = 0; j < max_lprefix; j++) -- if (etable[i,j]) -- print " ["i"]["j"] = "etable[i,j]"," -- print "};\n" -- # print group opcode map's array -- print "/* Group opcode map array */" -- print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ -- "[INAT_LSTPFX_MAX + 1] = {" -- for (i = 0; i < ggid; i++) -- for (j = 0; j < max_lprefix; j++) -- if (gtable[i,j]) -- print " ["i"]["j"] = "gtable[i,j]"," -- print "};\n" -- # print AVX opcode map's array -- print "/* AVX opcode map array */" -- print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ -- "[INAT_LSTPFX_MAX + 1] = {" -- for (i = 0; i < gaid; i++) -- for (j = 0; j < max_lprefix; j++) -- if (atable[i,j]) -- print " ["i"]["j"] = "atable[i,j]"," -- print "};" --} -- -diff --git a/tools/objtool/arch/x86/insn/inat.c b/tools/objtool/arch/x86/insn/inat.c -deleted file mode 100644 -index e4bf28e..0000000 ---- a/tools/objtool/arch/x86/insn/inat.c -+++ /dev/null -@@ -1,97 +0,0 @@ --/* -- * x86 instruction attribute tables -- * -- * Written by Masami Hiramatsu <mhiramat@redhat.com> -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, write to the Free Software -- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- * -- */ --#include "insn.h" -- --/* Attribute tables are generated from opcode map */ --#include "inat-tables.c" -- --/* Attribute search APIs */ --insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) --{ -- return inat_primary_table[opcode]; --} -- --int inat_get_last_prefix_id(insn_byte_t last_pfx) --{ -- insn_attr_t lpfx_attr; -- -- lpfx_attr = inat_get_opcode_attribute(last_pfx); -- return inat_last_prefix_id(lpfx_attr); --} -- --insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, -- insn_attr_t esc_attr) --{ -- const insn_attr_t *table; -- int n; -- -- n = inat_escape_id(esc_attr); -- -- table = inat_escape_tables[n][0]; -- if (!table) -- return 0; -- if (inat_has_variant(table[opcode]) && lpfx_id) { -- table = inat_escape_tables[n][lpfx_id]; -- if (!table) -- return 0; -- } -- return table[opcode]; --} -- --insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, -- insn_attr_t grp_attr) --{ -- const insn_attr_t *table; -- int n; -- -- n = inat_group_id(grp_attr); -- -- table = inat_group_tables[n][0]; -- if (!table) -- return inat_group_common_attribute(grp_attr); -- if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { -- table = inat_group_tables[n][lpfx_id]; -- if (!table) -- return inat_group_common_attribute(grp_attr); -- } -- return table[X86_MODRM_REG(modrm)] | -- inat_group_common_attribute(grp_attr); --} -- --insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, -- insn_byte_t vex_p) --{ -- const insn_attr_t *table; -- if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) -- return 0; -- /* At first, this checks the master table */ -- table = inat_avx_tables[vex_m][0]; -- if (!table) -- return 0; -- if (!inat_is_group(table[opcode]) && vex_p) { -- /* If this is not a group, get attribute directly */ -- table = inat_avx_tables[vex_m][vex_p]; -- if (!table) -- return 0; -- } -- return table[opcode]; --} -- -diff --git a/tools/objtool/arch/x86/insn/inat.h b/tools/objtool/arch/x86/insn/inat.h -deleted file mode 100644 -index 125ecd2..0000000 ---- a/tools/objtool/arch/x86/insn/inat.h -+++ /dev/null -@@ -1,234 +0,0 @@ --#ifndef _ASM_X86_INAT_H --#define _ASM_X86_INAT_H --/* -- * x86 instruction attributes -- * -- * Written by Masami Hiramatsu <mhiramat@redhat.com> -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, write to the Free Software -- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- * -- */ --#include "inat_types.h" -- --/* -- * Internal bits. Don't use bitmasks directly, because these bits are -- * unstable. You should use checking functions. -- */ -- --#define INAT_OPCODE_TABLE_SIZE 256 --#define INAT_GROUP_TABLE_SIZE 8 -- --/* Legacy last prefixes */ --#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ --#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ --#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ --/* Other Legacy prefixes */ --#define INAT_PFX_LOCK 4 /* 0xF0 */ --#define INAT_PFX_CS 5 /* 0x2E */ --#define INAT_PFX_DS 6 /* 0x3E */ --#define INAT_PFX_ES 7 /* 0x26 */ --#define INAT_PFX_FS 8 /* 0x64 */ --#define INAT_PFX_GS 9 /* 0x65 */ --#define INAT_PFX_SS 10 /* 0x36 */ --#define INAT_PFX_ADDRSZ 11 /* 0x67 */ --/* x86-64 REX prefix */ --#define INAT_PFX_REX 12 /* 0x4X */ --/* AVX VEX prefixes */ --#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ --#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ --#define INAT_PFX_EVEX 15 /* EVEX prefix */ -- --#define INAT_LSTPFX_MAX 3 --#define INAT_LGCPFX_MAX 11 -- --/* Immediate size */ --#define INAT_IMM_BYTE 1 --#define INAT_IMM_WORD 2 --#define INAT_IMM_DWORD 3 --#define INAT_IMM_QWORD 4 --#define INAT_IMM_PTR 5 --#define INAT_IMM_VWORD32 6 --#define INAT_IMM_VWORD 7 -- --/* Legacy prefix */ --#define INAT_PFX_OFFS 0 --#define INAT_PFX_BITS 4 --#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) --#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) --/* Escape opcodes */ --#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) --#define INAT_ESC_BITS 2 --#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) --#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) --/* Group opcodes (1-16) */ --#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) --#define INAT_GRP_BITS 5 --#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) --#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) --/* Immediates */ --#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) --#define INAT_IMM_BITS 3 --#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) --/* Flags */ --#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) --#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) --#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) --#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) --#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) --#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) --#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) --#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) --#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) --/* Attribute making macros for attribute tables */ --#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) --#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) --#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) --#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) -- --/* Attribute search APIs */ --extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); --extern int inat_get_last_prefix_id(insn_byte_t last_pfx); --extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, -- int lpfx_id, -- insn_attr_t esc_attr); --extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, -- int lpfx_id, -- insn_attr_t esc_attr); --extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, -- insn_byte_t vex_m, -- insn_byte_t vex_pp); -- --/* Attribute checking functions */ --static inline int inat_is_legacy_prefix(insn_attr_t attr) --{ -- attr &= INAT_PFX_MASK; -- return attr && attr <= INAT_LGCPFX_MAX; --} -- --static inline int inat_is_address_size_prefix(insn_attr_t attr) --{ -- return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; --} -- --static inline int inat_is_operand_size_prefix(insn_attr_t attr) --{ -- return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; --} -- --static inline int inat_is_rex_prefix(insn_attr_t attr) --{ -- return (attr & INAT_PFX_MASK) == INAT_PFX_REX; --} -- --static inline int inat_last_prefix_id(insn_attr_t attr) --{ -- if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) -- return 0; -- else -- return attr & INAT_PFX_MASK; --} -- --static inline int inat_is_vex_prefix(insn_attr_t attr) --{ -- attr &= INAT_PFX_MASK; -- return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || -- attr == INAT_PFX_EVEX; --} -- --static inline int inat_is_evex_prefix(insn_attr_t attr) --{ -- return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; --} -- --static inline int inat_is_vex3_prefix(insn_attr_t attr) --{ -- return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; --} -- --static inline int inat_is_escape(insn_attr_t attr) --{ -- return attr & INAT_ESC_MASK; --} -- --static inline int inat_escape_id(insn_attr_t attr) --{ -- return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; --} -- --static inline int inat_is_group(insn_attr_t attr) --{ -- return attr & INAT_GRP_MASK; --} -- --static inline int inat_group_id(insn_attr_t attr) --{ -- return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; --} -- --static inline int inat_group_common_attribute(insn_attr_t attr) --{ -- return attr & ~INAT_GRP_MASK; --} -- --static inline int inat_has_immediate(insn_attr_t attr) --{ -- return attr & INAT_IMM_MASK; --} -- --static inline int inat_immediate_size(insn_attr_t attr) --{ -- return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; --} -- --static inline int inat_has_modrm(insn_attr_t attr) --{ -- return attr & INAT_MODRM; --} -- --static inline int inat_is_force64(insn_attr_t attr) --{ -- return attr & INAT_FORCE64; --} -- --static inline int inat_has_second_immediate(insn_attr_t attr) --{ -- return attr & INAT_SCNDIMM; --} -- --static inline int inat_has_moffset(insn_attr_t attr) --{ -- return attr & INAT_MOFFSET; --} -- --static inline int inat_has_variant(insn_attr_t attr) --{ -- return attr & INAT_VARIANT; --} -- --static inline int inat_accept_vex(insn_attr_t attr) --{ -- return attr & INAT_VEXOK; --} -- --static inline int inat_must_vex(insn_attr_t attr) --{ -- return attr & (INAT_VEXONLY | INAT_EVEXONLY); --} -- --static inline int inat_must_evex(insn_attr_t attr) --{ -- return attr & INAT_EVEXONLY; --} --#endif -diff --git a/tools/objtool/arch/x86/insn/inat_types.h b/tools/objtool/arch/x86/insn/inat_types.h -deleted file mode 100644 -index cb3c20c..0000000 ---- a/tools/objtool/arch/x86/insn/inat_types.h -+++ /dev/null -@@ -1,29 +0,0 @@ --#ifndef _ASM_X86_INAT_TYPES_H --#define _ASM_X86_INAT_TYPES_H --/* -- * x86 instruction attributes -- * -- * Written by Masami Hiramatsu <mhiramat@redhat.com> -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, write to the Free Software -- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- * -- */ -- --/* Instruction attributes */ --typedef unsigned int insn_attr_t; --typedef unsigned char insn_byte_t; --typedef signed int insn_value_t; -- --#endif -diff --git a/tools/objtool/arch/x86/insn/insn.c b/tools/objtool/arch/x86/insn/insn.c -deleted file mode 100644 -index ca983e2..0000000 ---- a/tools/objtool/arch/x86/insn/insn.c -+++ /dev/null -@@ -1,606 +0,0 @@ --/* -- * x86 instruction analysis -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, write to the Free Software -- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- * -- * Copyright (C) IBM Corporation, 2002, 2004, 2009 -- */ -- --#ifdef __KERNEL__ --#include <linux/string.h> --#else --#include <string.h> --#endif --#include "inat.h" --#include "insn.h" -- --/* Verify next sizeof(t) bytes can be on the same instruction */ --#define validate_next(t, insn, n) \ -- ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) -- --#define __get_next(t, insn) \ -- ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) -- --#define __peek_nbyte_next(t, insn, n) \ -- ({ t r = *(t*)((insn)->next_byte + n); r; }) -- --#define get_next(t, insn) \ -- ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) -- --#define peek_nbyte_next(t, insn, n) \ -- ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) -- --#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) -- --/** -- * insn_init() - initialize struct insn -- * @insn: &struct insn to be initialized -- * @kaddr: address (in kernel memory) of instruction (or copy thereof) -- * @x86_64: !0 for 64-bit kernel or 64-bit app -- */ --void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) --{ -- /* -- * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid -- * even if the input buffer is long enough to hold them. -- */ -- if (buf_len > MAX_INSN_SIZE) -- buf_len = MAX_INSN_SIZE; -- -- memset(insn, 0, sizeof(*insn)); -- insn->kaddr = kaddr; -- insn->end_kaddr = kaddr + buf_len; -- insn->next_byte = kaddr; -- insn->x86_64 = x86_64 ? 1 : 0; -- insn->opnd_bytes = 4; -- if (x86_64) -- insn->addr_bytes = 8; -- else -- insn->addr_bytes = 4; --} -- --/** -- * insn_get_prefixes - scan x86 instruction prefix bytes -- * @insn: &struct insn containing instruction -- * -- * Populates the @insn->prefixes bitmap, and updates @insn->next_byte -- * to point to the (first) opcode. No effect if @insn->prefixes.got -- * is already set. -- */ --void insn_get_prefixes(struct insn *insn) --{ -- struct insn_field *prefixes = &insn->prefixes; -- insn_attr_t attr; -- insn_byte_t b, lb; -- int i, nb; -- -- if (prefixes->got) -- return; -- -- nb = 0; -- lb = 0; -- b = peek_next(insn_byte_t, insn); -- attr = inat_get_opcode_attribute(b); -- while (inat_is_legacy_prefix(attr)) { -- /* Skip if same prefix */ -- for (i = 0; i < nb; i++) -- if (prefixes->bytes[i] == b) -- goto found; -- if (nb == 4) -- /* Invalid instruction */ -- break; -- prefixes->bytes[nb++] = b; -- if (inat_is_address_size_prefix(attr)) { -- /* address size switches 2/4 or 4/8 */ -- if (insn->x86_64) -- insn->addr_bytes ^= 12; -- else -- insn->addr_bytes ^= 6; -- } else if (inat_is_operand_size_prefix(attr)) { -- /* oprand size switches 2/4 */ -- insn->opnd_bytes ^= 6; -- } --found: -- prefixes->nbytes++; -- insn->next_byte++; -- lb = b; -- b = peek_next(insn_byte_t, insn); -- attr = inat_get_opcode_attribute(b); -- } -- /* Set the last prefix */ -- if (lb && lb != insn->prefixes.bytes[3]) { -- if (unlikely(insn->prefixes.bytes[3])) { -- /* Swap the last prefix */ -- b = insn->prefixes.bytes[3]; -- for (i = 0; i < nb; i++) -- if (prefixes->bytes[i] == lb) -- prefixes->bytes[i] = b; -- } -- insn->prefixes.bytes[3] = lb; -- } -- -- /* Decode REX prefix */ -- if (insn->x86_64) { -- b = peek_next(insn_byte_t, insn); -- attr = inat_get_opcode_attribute(b); -- if (inat_is_rex_prefix(attr)) { -- insn->rex_prefix.value = b; -- insn->rex_prefix.nbytes = 1; -- insn->next_byte++; -- if (X86_REX_W(b)) -- /* REX.W overrides opnd_size */ -- insn->opnd_bytes = 8; -- } -- } -- insn->rex_prefix.got = 1; -- -- /* Decode VEX prefix */ -- b = peek_next(insn_byte_t, insn); -- attr = inat_get_opcode_attribute(b); -- if (inat_is_vex_prefix(attr)) { -- insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); -- if (!insn->x86_64) { -- /* -- * In 32-bits mode, if the [7:6] bits (mod bits of -- * ModRM) on the second byte are not 11b, it is -- * LDS or LES or BOUND. -- */ -- if (X86_MODRM_MOD(b2) != 3) -- goto vex_end; -- } -- insn->vex_prefix.bytes[0] = b; -- insn->vex_prefix.bytes[1] = b2; -- if (inat_is_evex_prefix(attr)) { -- b2 = peek_nbyte_next(insn_byte_t, insn, 2); -- insn->vex_prefix.bytes[2] = b2; -- b2 = peek_nbyte_next(insn_byte_t, insn, 3); -- insn->vex_prefix.bytes[3] = b2; -- insn->vex_prefix.nbytes = 4; -- insn->next_byte += 4; -- if (insn->x86_64 && X86_VEX_W(b2)) -- /* VEX.W overrides opnd_size */ -- insn->opnd_bytes = 8; -- } else if (inat_is_vex3_prefix(attr)) { -- b2 = peek_nbyte_next(insn_byte_t, insn, 2); -- insn->vex_prefix.bytes[2] = b2; -- insn->vex_prefix.nbytes = 3; -- insn->next_byte += 3; -- if (insn->x86_64 && X86_VEX_W(b2)) -- /* VEX.W overrides opnd_size */ -- insn->opnd_bytes = 8; -- } else { -- /* -- * For VEX2, fake VEX3-like byte#2. -- * Makes it easier to decode vex.W, vex.vvvv, -- * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. -- */ -- insn->vex_prefix.bytes[2] = b2 & 0x7f; -- insn->vex_prefix.nbytes = 2; -- insn->next_byte += 2; -- } -- } --vex_end: -- insn->vex_prefix.got = 1; -- -- prefixes->got = 1; -- --err_out: -- return; --} -- --/** -- * insn_get_opcode - collect opcode(s) -- * @insn: &struct insn containing instruction -- * -- * Populates @insn->opcode, updates @insn->next_byte to point past the -- * opcode byte(s), and set @insn->attr (except for groups). -- * If necessary, first collects any preceding (prefix) bytes. -- * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got -- * is already 1. -- */ --void insn_get_opcode(struct insn *insn) --{ -- struct insn_field *opcode = &insn->opcode; -- insn_byte_t op; -- int pfx_id; -- if (opcode->got) -- return; -- if (!insn->prefixes.got) -- insn_get_prefixes(insn); -- -- /* Get first opcode */ -- op = get_next(insn_byte_t, insn); -- opcode->bytes[0] = op; -- opcode->nbytes = 1; -- -- /* Check if there is VEX prefix or not */ -- if (insn_is_avx(insn)) { -- insn_byte_t m, p; -- m = insn_vex_m_bits(insn); -- p = insn_vex_p_bits(insn); -- insn->attr = inat_get_avx_attribute(op, m, p); -- if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || -- (!inat_accept_vex(insn->attr) && -- !inat_is_group(insn->attr))) -- insn->attr = 0; /* This instruction is bad */ -- goto end; /* VEX has only 1 byte for opcode */ -- } -- -- insn->attr = inat_get_opcode_attribute(op); -- while (inat_is_escape(insn->attr)) { -- /* Get escaped opcode */ -- op = get_next(insn_byte_t, insn); -- opcode->bytes[opcode->nbytes++] = op; -- pfx_id = insn_last_prefix_id(insn); -- insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); -- } -- if (inat_must_vex(insn->attr)) -- insn->attr = 0; /* This instruction is bad */ --end: -- opcode->got = 1; -- --err_out: -- return; --} -- --/** -- * insn_get_modrm - collect ModRM byte, if any -- * @insn: &struct insn containing instruction -- * -- * Populates @insn->modrm and updates @insn->next_byte to point past the -- * ModRM byte, if any. If necessary, first collects the preceding bytes -- * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. -- */ --void insn_get_modrm(struct insn *insn) --{ -- struct insn_field *modrm = &insn->modrm; -- insn_byte_t pfx_id, mod; -- if (modrm->got) -- return; -- if (!insn->opcode.got) -- insn_get_opcode(insn); -- -- if (inat_has_modrm(insn->attr)) { -- mod = get_next(insn_byte_t, insn); -- modrm->value = mod; -- modrm->nbytes = 1; -- if (inat_is_group(insn->attr)) { -- pfx_id = insn_last_prefix_id(insn); -- insn->attr = inat_get_group_attribute(mod, pfx_id, -- insn->attr); -- if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) -- insn->attr = 0; /* This is bad */ -- } -- } -- -- if (insn->x86_64 && inat_is_force64(insn->attr)) -- insn->opnd_bytes = 8; -- modrm->got = 1; -- --err_out: -- return; --} -- -- --/** -- * insn_rip_relative() - Does instruction use RIP-relative addressing mode? -- * @insn: &struct insn containing instruction -- * -- * If necessary, first collects the instruction up to and including the -- * ModRM byte. No effect if @insn->x86_64 is 0. -- */ --int insn_rip_relative(struct insn *insn) --{ -- struct insn_field *modrm = &insn->modrm; -- -- if (!insn->x86_64) -- return 0; -- if (!modrm->got) -- insn_get_modrm(insn); -- /* -- * For rip-relative instructions, the mod field (top 2 bits) -- * is zero and the r/m field (bottom 3 bits) is 0x5. -- */ -- return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); --} -- --/** -- * insn_get_sib() - Get the SIB byte of instruction -- * @insn: &struct insn containing instruction -- * -- * If necessary, first collects the instruction up to and including the -- * ModRM byte. -- */ --void insn_get_sib(struct insn *insn) --{ -- insn_byte_t modrm; -- -- if (insn->sib.got) -- return; -- if (!insn->modrm.got) -- insn_get_modrm(insn); -- if (insn->modrm.nbytes) { -- modrm = (insn_byte_t)insn->modrm.value; -- if (insn->addr_bytes != 2 && -- X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { -- insn->sib.value = get_next(insn_byte_t, insn); -- insn->sib.nbytes = 1; -- } -- } -- insn->sib.got = 1; -- --err_out: -- return; --} -- -- --/** -- * insn_get_displacement() - Get the displacement of instruction -- * @insn: &struct insn containing instruction -- * -- * If necessary, first collects the instruction up to and including the -- * SIB byte. -- * Displacement value is sign-expanded. -- */ --void insn_get_displacement(struct insn *insn) --{ -- insn_byte_t mod, rm, base; -- -- if (insn->displacement.got) -- return; -- if (!insn->sib.got) -- insn_get_sib(insn); -- if (insn->modrm.nbytes) { -- /* -- * Interpreting the modrm byte: -- * mod = 00 - no displacement fields (exceptions below) -- * mod = 01 - 1-byte displacement field -- * mod = 10 - displacement field is 4 bytes, or 2 bytes if -- * address size = 2 (0x67 prefix in 32-bit mode) -- * mod = 11 - no memory operand -- * -- * If address size = 2... -- * mod = 00, r/m = 110 - displacement field is 2 bytes -- * -- * If address size != 2... -- * mod != 11, r/m = 100 - SIB byte exists -- * mod = 00, SIB base = 101 - displacement field is 4 bytes -- * mod = 00, r/m = 101 - rip-relative addressing, displacement -- * field is 4 bytes -- */ -- mod = X86_MODRM_MOD(insn->modrm.value); -- rm = X86_MODRM_RM(insn->modrm.value); -- base = X86_SIB_BASE(insn->sib.value); -- if (mod == 3) -- goto out; -- if (mod == 1) { -- insn->displacement.value = get_next(signed char, insn); -- insn->displacement.nbytes = 1; -- } else if (insn->addr_bytes == 2) { -- if ((mod == 0 && rm == 6) || mod == 2) { -- insn->displacement.value = -- get_next(short, insn); -- insn->displacement.nbytes = 2; -- } -- } else { -- if ((mod == 0 && rm == 5) || mod == 2 || -- (mod == 0 && base == 5)) { -- insn->displacement.value = get_next(int, insn); -- insn->displacement.nbytes = 4; -- } -- } -- } --out: -- insn->displacement.got = 1; -- --err_out: -- return; --} -- --/* Decode moffset16/32/64. Return 0 if failed */ --static int __get_moffset(struct insn *insn) --{ -- switch (insn->addr_bytes) { -- case 2: -- insn->moffset1.value = get_next(short, insn); -- insn->moffset1.nbytes = 2; -- break; -- case 4: -- insn->moffset1.value = get_next(int, insn); -- insn->moffset1.nbytes = 4; -- break; -- case 8: -- insn->moffset1.value = get_next(int, insn); -- insn->moffset1.nbytes = 4; -- insn->moffset2.value = get_next(int, insn); -- insn->moffset2.nbytes = 4; -- break; -- default: /* opnd_bytes must be modified manually */ -- goto err_out; -- } -- insn->moffset1.got = insn->moffset2.got = 1; -- -- return 1; -- --err_out: -- return 0; --} -- --/* Decode imm v32(Iz). Return 0 if failed */ --static int __get_immv32(struct insn *insn) --{ -- switch (insn->opnd_bytes) { -- case 2: -- insn->immediate.value = get_next(short, insn); -- insn->immediate.nbytes = 2; -- break; -- case 4: -- case 8: -- insn->immediate.value = get_next(int, insn); -- insn->immediate.nbytes = 4; -- break; -- default: /* opnd_bytes must be modified manually */ -- goto err_out; -- } -- -- return 1; -- --err_out: -- return 0; --} -- --/* Decode imm v64(Iv/Ov), Return 0 if failed */ --static int __get_immv(struct insn *insn) --{ -- switch (insn->opnd_bytes) { -- case 2: -- insn->immediate1.value = get_next(short, insn); -- insn->immediate1.nbytes = 2; -- break; -- case 4: -- insn->immediate1.value = get_next(int, insn); -- insn->immediate1.nbytes = 4; -- break; -- case 8: -- insn->immediate1.value = get_next(int, insn); -- insn->immediate1.nbytes = 4; -- insn->immediate2.value = get_next(int, insn); -- insn->immediate2.nbytes = 4; -- break; -- default: /* opnd_bytes must be modified manually */ -- goto err_out; -- } -- insn->immediate1.got = insn->immediate2.got = 1; -- -- return 1; --err_out: -- return 0; --} -- --/* Decode ptr16:16/32(Ap) */ --static int __get_immptr(struct insn *insn) --{ -- switch (insn->opnd_bytes) { -- case 2: -- insn->immediate1.value = get_next(short, insn); -- insn->immediate1.nbytes = 2; -- break; -- case 4: -- insn->immediate1.value = get_next(int, insn); -- insn->immediate1.nbytes = 4; -- break; -- case 8: -- /* ptr16:64 is not exist (no segment) */ -- return 0; -- default: /* opnd_bytes must be modified manually */ -- goto err_out; -- } -- insn->immediate2.value = get_next(unsigned short, insn); -- insn->immediate2.nbytes = 2; -- insn->immediate1.got = insn->immediate2.got = 1; -- -- return 1; --err_out: -- return 0; --} -- --/** -- * insn_get_immediate() - Get the immediates of instruction -- * @insn: &struct insn containing instruction -- * -- * If necessary, first collects the instruction up to and including the -- * displacement bytes. -- * Basically, most of immediates are sign-expanded. Unsigned-value can be -- * get by bit masking with ((1 << (nbytes * 8)) - 1) -- */ --void insn_get_immediate(struct insn *insn) --{ -- if (insn->immediate.got) -- return; -- if (!insn->displacement.got) -- insn_get_displacement(insn); -- -- if (inat_has_moffset(insn->attr)) { -- if (!__get_moffset(insn)) -- goto err_out; -- goto done; -- } -- -- if (!inat_has_immediate(insn->attr)) -- /* no immediates */ -- goto done; -- -- switch (inat_immediate_size(insn->attr)) { -- case INAT_IMM_BYTE: -- insn->immediate.value = get_next(signed char, insn); -- insn->immediate.nbytes = 1; -- break; -- case INAT_IMM_WORD: -- insn->immediate.value = get_next(short, insn); -- insn->immediate.nbytes = 2; -- break; -- case INAT_IMM_DWORD: -- insn->immediate.value = get_next(int, insn); -- insn->immediate.nbytes = 4; -- break; -- case INAT_IMM_QWORD: -- insn->immediate1.value = get_next(int, insn); -- insn->immediate1.nbytes = 4; -- insn->immediate2.value = get_next(int, insn); -- insn->immediate2.nbytes = 4; -- break; -- case INAT_IMM_PTR: -- if (!__get_immptr(insn)) -- goto err_out; -- break; -- case INAT_IMM_VWORD32: -- if (!__get_immv32(insn)) -- goto err_out; -- break; -- case INAT_IMM_VWORD: -- if (!__get_immv(insn)) -- goto err_out; -- break; -- default: -- /* Here, insn must have an immediate, but failed */ -- goto err_out; -- } -- if (inat_has_second_immediate(insn->attr)) { -- insn->immediate2.value = get_next(signed char, insn); -- insn->immediate2.nbytes = 1; -- } --done: -- insn->immediate.got = 1; -- --err_out: -- return; --} -- --/** -- * insn_get_length() - Get the length of instruction -- * @insn: &struct insn containing instruction -- * -- * If necessary, first collects the instruction up to and including the -- * immediates bytes. -- */ --void insn_get_length(struct insn *insn) --{ -- if (insn->length) -- return; -- if (!insn->immediate.got) -- insn_get_immediate(insn); -- insn->length = (unsigned char)((unsigned long)insn->next_byte -- - (unsigned long)insn->kaddr); --} -diff --git a/tools/objtool/arch/x86/insn/insn.h b/tools/objtool/arch/x86/insn/insn.h -deleted file mode 100644 -index e23578c..0000000 ---- a/tools/objtool/arch/x86/insn/insn.h -+++ /dev/null -@@ -1,211 +0,0 @@ --#ifndef _ASM_X86_INSN_H --#define _ASM_X86_INSN_H --/* -- * x86 instruction analysis -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program; if not, write to the Free Software -- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- * -- * Copyright (C) IBM Corporation, 2009 -- */ -- --/* insn_attr_t is defined in inat.h */ --#include "inat.h" -- --struct insn_field { -- union { -- insn_value_t value; -- insn_byte_t bytes[4]; -- }; -- /* !0 if we've run insn_get_xxx() for this field */ -- unsigned char got; -- unsigned char nbytes; --}; -- --struct insn { -- struct insn_field prefixes; /* -- * Prefixes -- * prefixes.bytes[3]: last prefix -- */ -- struct insn_field rex_prefix; /* REX prefix */ -- struct insn_field vex_prefix; /* VEX prefix */ -- struct insn_field opcode; /* -- * opcode.bytes[0]: opcode1 -- * opcode.bytes[1]: opcode2 -- * opcode.bytes[2]: opcode3 -- */ -- struct insn_field modrm; -- struct insn_field sib; -- struct insn_field displacement; -- union { -- struct insn_field immediate; -- struct insn_field moffset1; /* for 64bit MOV */ -- struct insn_field immediate1; /* for 64bit imm or off16/32 */ -- }; -- union { -- struct insn_field moffset2; /* for 64bit MOV */ -- struct insn_field immediate2; /* for 64bit imm or seg16 */ -- }; -- -- insn_attr_t attr; -- unsigned char opnd_bytes; -- unsigned char addr_bytes; -- unsigned char length; -- unsigned char x86_64; -- -- const insn_byte_t *kaddr; /* kernel address of insn to analyze */ -- const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ -- const insn_byte_t *next_byte; --}; -- --#define MAX_INSN_SIZE 15 -- --#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) --#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) --#define X86_MODRM_RM(modrm) ((modrm) & 0x07) -- --#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) --#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) --#define X86_SIB_BASE(sib) ((sib) & 0x07) -- --#define X86_REX_W(rex) ((rex) & 8) --#define X86_REX_R(rex) ((rex) & 4) --#define X86_REX_X(rex) ((rex) & 2) --#define X86_REX_B(rex) ((rex) & 1) -- --/* VEX bit flags */ --#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ --#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ --#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ --#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ --#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ --/* VEX bit fields */ --#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ --#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ --#define X86_VEX2_M 1 /* VEX2.M always 1 */ --#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ --#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ --#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ -- --extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); --extern void insn_get_prefixes(struct insn *insn); --extern void insn_get_opcode(struct insn *insn); --extern void insn_get_modrm(struct insn *insn); --extern void insn_get_sib(struct insn *insn); --extern void insn_get_displacement(struct insn *insn); --extern void insn_get_immediate(struct insn *insn); --extern void insn_get_length(struct insn *insn); -- --/* Attribute will be determined after getting ModRM (for opcode groups) */ --static inline void insn_get_attribute(struct insn *insn) --{ -- insn_get_modrm(insn); --} -- --/* Instruction uses RIP-relative addressing */ --extern int insn_rip_relative(struct insn *insn); -- --/* Init insn for kernel text */ --static inline void kernel_insn_init(struct insn *insn, -- const void *kaddr, int buf_len) --{ --#ifdef CONFIG_X86_64 -- insn_init(insn, kaddr, buf_len, 1); --#else /* CONFIG_X86_32 */ -- insn_init(insn, kaddr, buf_len, 0); --#endif --} -- --static inline int insn_is_avx(struct insn *insn) --{ -- if (!insn->prefixes.got) -- insn_get_prefixes(insn); -- return (insn->vex_prefix.value != 0); --} -- --static inline int insn_is_evex(struct insn *insn) --{ -- if (!insn->prefixes.got) -- insn_get_prefixes(insn); -- return (insn->vex_prefix.nbytes == 4); --} -- --/* Ensure this instruction is decoded completely */ --static inline int insn_complete(struct insn *insn) --{ -- return insn->opcode.got && insn->modrm.got && insn->sib.got && -- insn->displacement.got && insn->immediate.got; --} -- --static inline insn_byte_t insn_vex_m_bits(struct insn *insn) --{ -- if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ -- return X86_VEX2_M; -- else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ -- return X86_VEX3_M(insn->vex_prefix.bytes[1]); -- else /* EVEX */ -- return X86_EVEX_M(insn->vex_prefix.bytes[1]); --} -- --static inline insn_byte_t insn_vex_p_bits(struct insn *insn) --{ -- if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ -- return X86_VEX_P(insn->vex_prefix.bytes[1]); -- else -- return X86_VEX_P(insn->vex_prefix.bytes[2]); --} -- --/* Get the last prefix id from last prefix or VEX prefix */ --static inline int insn_last_prefix_id(struct insn *insn) --{ -- if (insn_is_avx(insn)) -- return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ -- -- if (insn->prefixes.bytes[3]) -- return inat_get_last_prefix_id(insn->prefixes.bytes[3]); -- -- return 0; --} -- --/* Offset of each field from kaddr */ --static inline int insn_offset_rex_prefix(struct insn *insn) --{ -- return insn->prefixes.nbytes; --} --static inline int insn_offset_vex_prefix(struct insn *insn) --{ -- return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; --} --static inline int insn_offset_opcode(struct insn *insn) --{ -- return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; --} --static inline int insn_offset_modrm(struct insn *insn) --{ -- return insn_offset_opcode(insn) + insn->opcode.nbytes; --} --static inline int insn_offset_sib(struct insn *insn) --{ -- return insn_offset_modrm(insn) + insn->modrm.nbytes; --} --static inline int insn_offset_displacement(struct insn *insn) --{ -- return insn_offset_sib(insn) + insn->sib.nbytes; --} --static inline int insn_offset_immediate(struct insn *insn) --{ -- return insn_offset_displacement(insn) + insn->displacement.nbytes; --} -- --#endif /* _ASM_X86_INSN_H */ -diff --git a/tools/objtool/arch/x86/insn/x86-opcode-map.txt b/tools/objtool/arch/x86/insn/x86-opcode-map.txt -deleted file mode 100644 -index 767be7c..0000000 ---- a/tools/objtool/arch/x86/insn/x86-opcode-map.txt -+++ /dev/null -@@ -1,1063 +0,0 @@ --# x86 Opcode Maps --# --# This is (mostly) based on following documentations. --# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C --# (#326018-047US, June 2013) --# --#<Opcode maps> --# Table: table-name --# Referrer: escaped-name --# AVXcode: avx-code --# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] --# (or) --# opcode: escape # escaped-name --# EndTable --# --# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix --# mnemonics that begin with lowercase 'k' accept a VEX prefix --# --#<group maps> --# GrpTable: GrpXXX --# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] --# EndTable --# --# AVX Superscripts --# (ev): this opcode requires EVEX prefix. --# (evo): this opcode is changed by EVEX prefix (EVEX opcode) --# (v): this opcode requires VEX prefix. --# (v1): this opcode only supports 128bit VEX. --# --# Last Prefix Superscripts --# - (66): the last prefix is 0x66 --# - (F3): the last prefix is 0xF3 --# - (F2): the last prefix is 0xF2 --# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) --# - (66&F2): Both 0x66 and 0xF2 prefixes are specified. -- --Table: one byte opcode --Referrer: --AVXcode: --# 0x00 - 0x0f --00: ADD Eb,Gb --01: ADD Ev,Gv --02: ADD Gb,Eb --03: ADD Gv,Ev --04: ADD AL,Ib --05: ADD rAX,Iz --06: PUSH ES (i64) --07: POP ES (i64) --08: OR Eb,Gb --09: OR Ev,Gv --0a: OR Gb,Eb --0b: OR Gv,Ev --0c: OR AL,Ib --0d: OR rAX,Iz --0e: PUSH CS (i64) --0f: escape # 2-byte escape --# 0x10 - 0x1f --10: ADC Eb,Gb --11: ADC Ev,Gv --12: ADC Gb,Eb --13: ADC Gv,Ev --14: ADC AL,Ib --15: ADC rAX,Iz --16: PUSH SS (i64) --17: POP SS (i64) --18: SBB Eb,Gb --19: SBB Ev,Gv --1a: SBB Gb,Eb --1b: SBB Gv,Ev --1c: SBB AL,Ib --1d: SBB rAX,Iz --1e: PUSH DS (i64) --1f: POP DS (i64) --# 0x20 - 0x2f --20: AND Eb,Gb --21: AND Ev,Gv --22: AND Gb,Eb --23: AND Gv,Ev --24: AND AL,Ib --25: AND rAx,Iz --26: SEG=ES (Prefix) --27: DAA (i64) --28: SUB Eb,Gb --29: SUB Ev,Gv --2a: SUB Gb,Eb --2b: SUB Gv,Ev --2c: SUB AL,Ib --2d: SUB rAX,Iz --2e: SEG=CS (Prefix) --2f: DAS (i64) --# 0x30 - 0x3f --30: XOR Eb,Gb --31: XOR Ev,Gv --32: XOR Gb,Eb --33: XOR Gv,Ev --34: XOR AL,Ib --35: XOR rAX,Iz --36: SEG=SS (Prefix) --37: AAA (i64) --38: CMP Eb,Gb --39: CMP Ev,Gv --3a: CMP Gb,Eb --3b: CMP Gv,Ev --3c: CMP AL,Ib --3d: CMP rAX,Iz --3e: SEG=DS (Prefix) --3f: AAS (i64) --# 0x40 - 0x4f --40: INC eAX (i64) | REX (o64) --41: INC eCX (i64) | REX.B (o64) --42: INC eDX (i64) | REX.X (o64) --43: INC eBX (i64) | REX.XB (o64) --44: INC eSP (i64) | REX.R (o64) --45: INC eBP (i64) | REX.RB (o64) --46: INC eSI (i64) | REX.RX (o64) --47: INC eDI (i64) | REX.RXB (o64) --48: DEC eAX (i64) | REX.W (o64) --49: DEC eCX (i64) | REX.WB (o64) --4a: DEC eDX (i64) | REX.WX (o64) --4b: DEC eBX (i64) | REX.WXB (o64) --4c: DEC eSP (i64) | REX.WR (o64) --4d: DEC eBP (i64) | REX.WRB (o64) --4e: DEC eSI (i64) | REX.WRX (o64) --4f: DEC eDI (i64) | REX.WRXB (o64) --# 0x50 - 0x5f --50: PUSH rAX/r8 (d64) --51: PUSH rCX/r9 (d64) --52: PUSH rDX/r10 (d64) --53: PUSH rBX/r11 (d64) --54: PUSH rSP/r12 (d64) --55: PUSH rBP/r13 (d64) --56: PUSH rSI/r14 (d64) --57: PUSH rDI/r15 (d64) --58: POP rAX/r8 (d64) --59: POP rCX/r9 (d64) --5a: POP rDX/r10 (d64) --5b: POP rBX/r11 (d64) --5c: POP rSP/r12 (d64) --5d: POP rBP/r13 (d64) --5e: POP rSI/r14 (d64) --5f: POP rDI/r15 (d64) --# 0x60 - 0x6f --60: PUSHA/PUSHAD (i64) --61: POPA/POPAD (i64) --62: BOUND Gv,Ma (i64) | EVEX (Prefix) --63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) --64: SEG=FS (Prefix) --65: SEG=GS (Prefix) --66: Operand-Size (Prefix) --67: Address-Size (Prefix) --68: PUSH Iz (d64) --69: IMUL Gv,Ev,Iz --6a: PUSH Ib (d64) --6b: IMUL Gv,Ev,Ib --6c: INS/INSB Yb,DX --6d: INS/INSW/INSD Yz,DX --6e: OUTS/OUTSB DX,Xb --6f: OUTS/OUTSW/OUTSD DX,Xz --# 0x70 - 0x7f --70: JO Jb --71: JNO Jb --72: JB/JNAE/JC Jb --73: JNB/JAE/JNC Jb --74: JZ/JE Jb --75: JNZ/JNE Jb --76: JBE/JNA Jb --77: JNBE/JA Jb --78: JS Jb --79: JNS Jb --7a: JP/JPE Jb --7b: JNP/JPO Jb --7c: JL/JNGE Jb --7d: JNL/JGE Jb --7e: JLE/JNG Jb --7f: JNLE/JG Jb --# 0x80 - 0x8f --80: Grp1 Eb,Ib (1A) --81: Grp1 Ev,Iz (1A) --82: Grp1 Eb,Ib (1A),(i64) --83: Grp1 Ev,Ib (1A) --84: TEST Eb,Gb --85: TEST Ev,Gv --86: XCHG Eb,Gb --87: XCHG Ev,Gv --88: MOV Eb,Gb --89: MOV Ev,Gv --8a: MOV Gb,Eb --8b: MOV Gv,Ev --8c: MOV Ev,Sw --8d: LEA Gv,M --8e: MOV Sw,Ew --8f: Grp1A (1A) | POP Ev (d64) --# 0x90 - 0x9f --90: NOP | PAUSE (F3) | XCHG r8,rAX --91: XCHG rCX/r9,rAX --92: XCHG rDX/r10,rAX --93: XCHG rBX/r11,rAX --94: XCHG rSP/r12,rAX --95: XCHG rBP/r13,rAX --96: XCHG rSI/r14,rAX --97: XCHG rDI/r15,rAX --98: CBW/CWDE/CDQE --99: CWD/CDQ/CQO --9a: CALLF Ap (i64) --9b: FWAIT/WAIT --9c: PUSHF/D/Q Fv (d64) --9d: POPF/D/Q Fv (d64) --9e: SAHF --9f: LAHF --# 0xa0 - 0xaf --a0: MOV AL,Ob --a1: MOV rAX,Ov --a2: MOV Ob,AL --a3: MOV Ov,rAX --a4: MOVS/B Yb,Xb --a5: MOVS/W/D/Q Yv,Xv --a6: CMPS/B Xb,Yb --a7: CMPS/W/D Xv,Yv --a8: TEST AL,Ib --a9: TEST rAX,Iz --aa: STOS/B Yb,AL --ab: STOS/W/D/Q Yv,rAX --ac: LODS/B AL,Xb --ad: LODS/W/D/Q rAX,Xv --ae: SCAS/B AL,Yb --# Note: The May 2011 Intel manual shows Xv for the second parameter of the --# next instruction but Yv is correct --af: SCAS/W/D/Q rAX,Yv --# 0xb0 - 0xbf --b0: MOV AL/R8L,Ib --b1: MOV CL/R9L,Ib --b2: MOV DL/R10L,Ib --b3: MOV BL/R11L,Ib --b4: MOV AH/R12L,Ib --b5: MOV CH/R13L,Ib --b6: MOV DH/R14L,Ib --b7: MOV BH/R15L,Ib --b8: MOV rAX/r8,Iv --b9: MOV rCX/r9,Iv --ba: MOV rDX/r10,Iv --bb: MOV rBX/r11,Iv --bc: MOV rSP/r12,Iv --bd: MOV rBP/r13,Iv --be: MOV rSI/r14,Iv --bf: MOV rDI/r15,Iv --# 0xc0 - 0xcf --c0: Grp2 Eb,Ib (1A) --c1: Grp2 Ev,Ib (1A) --c2: RETN Iw (f64) --c3: RETN --c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) --c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) --c6: Grp11A Eb,Ib (1A) --c7: Grp11B Ev,Iz (1A) --c8: ENTER Iw,Ib --c9: LEAVE (d64) --ca: RETF Iw --cb: RETF --cc: INT3 --cd: INT Ib --ce: INTO (i64) --cf: IRET/D/Q --# 0xd0 - 0xdf --d0: Grp2 Eb,1 (1A) --d1: Grp2 Ev,1 (1A) --d2: Grp2 Eb,CL (1A) --d3: Grp2 Ev,CL (1A) --d4: AAM Ib (i64) --d5: AAD Ib (i64) --d6: --d7: XLAT/XLATB --d8: ESC --d9: ESC --da: ESC --db: ESC --dc: ESC --dd: ESC --de: ESC --df: ESC --# 0xe0 - 0xef --# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix --# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation --# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD. --e0: LOOPNE/LOOPNZ Jb (f64) --e1: LOOPE/LOOPZ Jb (f64) --e2: LOOP Jb (f64) --e3: JrCXZ Jb (f64) --e4: IN AL,Ib --e5: IN eAX,Ib --e6: OUT Ib,AL --e7: OUT Ib,eAX --# With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset --# in "near" jumps and calls is 16-bit. For CALL, --# push of return address is 16-bit wide, RSP is decremented by 2 --# but is not truncated to 16 bits, unlike RIP. --e8: CALL Jz (f64) --e9: JMP-near Jz (f64) --ea: JMP-far Ap (i64) --eb: JMP-short Jb (f64) --ec: IN AL,DX --ed: IN eAX,DX --ee: OUT DX,AL --ef: OUT DX,eAX --# 0xf0 - 0xff --f0: LOCK (Prefix) --f1: --f2: REPNE (Prefix) | XACQUIRE (Prefix) --f3: REP/REPE (Prefix) | XRELEASE (Prefix) --f4: HLT --f5: CMC --f6: Grp3_1 Eb (1A) --f7: Grp3_2 Ev (1A) --f8: CLC --f9: STC --fa: CLI --fb: STI --fc: CLD --fd: STD --fe: Grp4 (1A) --ff: Grp5 (1A) --EndTable -- --Table: 2-byte opcode (0x0f) --Referrer: 2-byte escape --AVXcode: 1 --# 0x0f 0x00-0x0f --00: Grp6 (1A) --01: Grp7 (1A) --02: LAR Gv,Ew --03: LSL Gv,Ew --04: --05: SYSCALL (o64) --06: CLTS --07: SYSRET (o64) --08: INVD --09: WBINVD --0a: --0b: UD2 (1B) --0c: --# AMD's prefetch group. Intel supports prefetchw(/1) only. --0d: GrpP --0e: FEMMS --# 3DNow! uses the last imm byte as opcode extension. --0f: 3DNow! Pq,Qq,Ib --# 0x0f 0x10-0x1f --# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands --# but it actually has operands. And also, vmovss and vmovsd only accept 128bit. --# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. --# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming --# Reference A.1 --10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) --11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) --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) --13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) --14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) --15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) --16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) --17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) --18: Grp16 (1A) --19: --# Intel SDM opcode map does not list MPX instructions. For now using Gv for --# bnd registers and Ev for everything else is OK because the instruction --# decoder does not use the information except as an indication that there is --# a ModR/M byte. --1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev --1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv --1c: --1d: --1e: --1f: NOP Ev --# 0x0f 0x20-0x2f --20: MOV Rd,Cd --21: MOV Rd,Dd --22: MOV Cd,Rd --23: MOV Dd,Rd --24: --25: --26: --27: --28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) --29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) --2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) --2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) --2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) --2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) --2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) --2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) --# 0x0f 0x30-0x3f --30: WRMSR --31: RDTSC --32: RDMSR --33: RDPMC --34: SYSENTER --35: SYSEXIT --36: --37: GETSEC --38: escape # 3-byte escape 1 --39: --3a: escape # 3-byte escape 2 --3b: --3c: --3d: --3e: --3f: --# 0x0f 0x40-0x4f --40: CMOVO Gv,Ev --41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) --42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) --43: CMOVAE/NB/NC Gv,Ev --44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) --45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) --46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) --47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) --48: CMOVS Gv,Ev --49: CMOVNS Gv,Ev --4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) --4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk --4c: CMOVL/NGE Gv,Ev --4d: CMOVNL/GE Gv,Ev --4e: CMOVLE/NG Gv,Ev --4f: CMOVNLE/G Gv,Ev --# 0x0f 0x50-0x5f --50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) --51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) --52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) --53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) --54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) --55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) --56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) --57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) --58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) --59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) --5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) --5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) --5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) --5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) --5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) --5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) --# 0x0f 0x60-0x6f --60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) --61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) --62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) --63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) --64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) --65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) --66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) --67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) --68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) --69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) --6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) --6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) --6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) --6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) --6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) --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) --# 0x0f 0x70-0x7f --70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) --71: Grp12 (1A) --72: Grp13 (1A) --73: Grp14 (1A) --74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) --75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) --76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) --# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. --77: emms | vzeroupper | vzeroall --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) --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) --7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) --7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) --7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) --7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) --7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) --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) --# 0x0f 0x80-0x8f --# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). --80: JO Jz (f64) --81: JNO Jz (f64) --82: JB/JC/JNAE Jz (f64) --83: JAE/JNB/JNC Jz (f64) --84: JE/JZ Jz (f64) --85: JNE/JNZ Jz (f64) --86: JBE/JNA Jz (f64) --87: JA/JNBE Jz (f64) --88: JS Jz (f64) --89: JNS Jz (f64) --8a: JP/JPE Jz (f64) --8b: JNP/JPO Jz (f64) --8c: JL/JNGE Jz (f64) --8d: JNL/JGE Jz (f64) --8e: JLE/JNG Jz (f64) --8f: JNLE/JG Jz (f64) --# 0x0f 0x90-0x9f --90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) --91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) --92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) --93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) --94: SETE/Z Eb --95: SETNE/NZ Eb --96: SETBE/NA Eb --97: SETA/NBE Eb --98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) --99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) --9a: SETP/PE Eb --9b: SETNP/PO Eb --9c: SETL/NGE Eb --9d: SETNL/GE Eb --9e: SETLE/NG Eb --9f: SETNLE/G Eb --# 0x0f 0xa0-0xaf --a0: PUSH FS (d64) --a1: POP FS (d64) --a2: CPUID --a3: BT Ev,Gv --a4: SHLD Ev,Gv,Ib --a5: SHLD Ev,Gv,CL --a6: GrpPDLK --a7: GrpRNG --a8: PUSH GS (d64) --a9: POP GS (d64) --aa: RSM --ab: BTS Ev,Gv --ac: SHRD Ev,Gv,Ib --ad: SHRD Ev,Gv,CL --ae: Grp15 (1A),(1C) --af: IMUL Gv,Ev --# 0x0f 0xb0-0xbf --b0: CMPXCHG Eb,Gb --b1: CMPXCHG Ev,Gv --b2: LSS Gv,Mp --b3: BTR Ev,Gv --b4: LFS Gv,Mp --b5: LGS Gv,Mp --b6: MOVZX Gv,Eb --b7: MOVZX Gv,Ew --b8: JMPE (!F3) | POPCNT Gv,Ev (F3) --b9: Grp10 (1A) --ba: Grp8 Ev,Ib (1A) --bb: BTC Ev,Gv --bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) --bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) --be: MOVSX Gv,Eb --bf: MOVSX Gv,Ew --# 0x0f 0xc0-0xcf --c0: XADD Eb,Gb --c1: XADD Ev,Gv --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) --c3: movnti My,Gy --c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) --c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) --c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) --c7: Grp9 (1A) --c8: BSWAP RAX/EAX/R8/R8D --c9: BSWAP RCX/ECX/R9/R9D --ca: BSWAP RDX/EDX/R10/R10D --cb: BSWAP RBX/EBX/R11/R11D --cc: BSWAP RSP/ESP/R12/R12D --cd: BSWAP RBP/EBP/R13/R13D --ce: BSWAP RSI/ESI/R14/R14D --cf: BSWAP RDI/EDI/R15/R15D --# 0x0f 0xd0-0xdf --d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) --d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) --d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) --d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) --d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) --d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) --d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) --d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) --d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) --d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) --da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) --db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) --dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) --dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) --de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) --df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) --# 0x0f 0xe0-0xef --e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) --e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) --e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) --e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) --e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) --e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) --e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) --e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) --e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) --e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) --ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) --eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) --ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) --ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) --ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) --ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) --# 0x0f 0xf0-0xff --f0: vlddqu Vx,Mx (F2) --f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) --f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) --f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) --f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) --f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) --f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) --f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) --f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) --f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) --fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) --fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) --fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) --fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) --fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) --ff: --EndTable -- --Table: 3-byte opcode 1 (0x0f 0x38) --Referrer: 3-byte escape 1 --AVXcode: 2 --# 0x0f 0x38 0x00-0x0f --00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) --01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) --02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) --03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) --04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) --05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) --06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) --07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) --08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) --09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) --0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) --0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) --0c: vpermilps Vx,Hx,Wx (66),(v) --0d: vpermilpd Vx,Hx,Wx (66),(v) --0e: vtestps Vx,Wx (66),(v) --0f: vtestpd Vx,Wx (66),(v) --# 0x0f 0x38 0x10-0x1f --10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) --11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) --12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) --13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) --14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) --15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) --16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) --17: vptest Vx,Wx (66) --18: vbroadcastss Vx,Wd (66),(v) --19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) --1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) --1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) --1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) --1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) --1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) --1f: vpabsq Vx,Wx (66),(ev) --# 0x0f 0x38 0x20-0x2f --20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) --21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) --22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) --23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) --24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) --25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) --26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) --27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) --28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) --29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) --2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) --2b: vpackusdw Vx,Hx,Wx (66),(v1) --2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) --2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) --2e: vmaskmovps Mx,Hx,Vx (66),(v) --2f: vmaskmovpd Mx,Hx,Vx (66),(v) --# 0x0f 0x38 0x30-0x3f --30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) --31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) --32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) --33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) --34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) --35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) --36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) --37: vpcmpgtq Vx,Hx,Wx (66),(v1) --38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) --39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) --3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) --3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) --3c: vpmaxsb Vx,Hx,Wx (66),(v1) --3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) --3e: vpmaxuw Vx,Hx,Wx (66),(v1) --3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) --# 0x0f 0x38 0x40-0x8f --40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) --41: vphminposuw Vdq,Wdq (66),(v1) --42: vgetexpps/d Vx,Wx (66),(ev) --43: vgetexpss/d Vx,Hx,Wx (66),(ev) --44: vplzcntd/q Vx,Wx (66),(ev) --45: vpsrlvd/q Vx,Hx,Wx (66),(v) --46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) --47: vpsllvd/q Vx,Hx,Wx (66),(v) --# Skip 0x48-0x4b --4c: vrcp14ps/d Vpd,Wpd (66),(ev) --4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) --4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) --4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) --# Skip 0x50-0x57 --58: vpbroadcastd Vx,Wx (66),(v) --59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) --5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) --5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) --# Skip 0x5c-0x63 --64: vpblendmd/q Vx,Hx,Wx (66),(ev) --65: vblendmps/d Vx,Hx,Wx (66),(ev) --66: vpblendmb/w Vx,Hx,Wx (66),(ev) --# Skip 0x67-0x74 --75: vpermi2b/w Vx,Hx,Wx (66),(ev) --76: vpermi2d/q Vx,Hx,Wx (66),(ev) --77: vpermi2ps/d Vx,Hx,Wx (66),(ev) --78: vpbroadcastb Vx,Wx (66),(v) --79: vpbroadcastw Vx,Wx (66),(v) --7a: vpbroadcastb Vx,Rv (66),(ev) --7b: vpbroadcastw Vx,Rv (66),(ev) --7c: vpbroadcastd/q Vx,Rv (66),(ev) --7d: vpermt2b/w Vx,Hx,Wx (66),(ev) --7e: vpermt2d/q Vx,Hx,Wx (66),(ev) --7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) --80: INVEPT Gy,Mdq (66) --81: INVPID Gy,Mdq (66) --82: INVPCID Gy,Mdq (66) --83: vpmultishiftqb Vx,Hx,Wx (66),(ev) --88: vexpandps/d Vpd,Wpd (66),(ev) --89: vpexpandd/q Vx,Wx (66),(ev) --8a: vcompressps/d Wx,Vx (66),(ev) --8b: vpcompressd/q Wx,Vx (66),(ev) --8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) --8d: vpermb/w Vx,Hx,Wx (66),(ev) --8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) --# 0x0f 0x38 0x90-0xbf (FMA) --90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) --91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) --92: vgatherdps/d Vx,Hx,Wx (66),(v) --93: vgatherqps/d Vx,Hx,Wx (66),(v) --94: --95: --96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) --97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) --98: vfmadd132ps/d Vx,Hx,Wx (66),(v) --99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) --9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) --9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) --9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) --9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) --9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) --9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) --a0: vpscatterdd/q Wx,Vx (66),(ev) --a1: vpscatterqd/q Wx,Vx (66),(ev) --a2: vscatterdps/d Wx,Vx (66),(ev) --a3: vscatterqps/d Wx,Vx (66),(ev) --a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) --a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) --a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) --a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) --aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) --ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) --ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) --ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) --ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) --af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) --b4: vpmadd52luq Vx,Hx,Wx (66),(ev) --b5: vpmadd52huq Vx,Hx,Wx (66),(ev) --b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) --b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) --b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) --b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) --ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) --bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) --bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) --bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) --be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) --bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) --# 0x0f 0x38 0xc0-0xff --c4: vpconflictd/q Vx,Wx (66),(ev) --c6: Grp18 (1A) --c7: Grp19 (1A) --c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) --c9: sha1msg1 Vdq,Wdq --ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) --cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) --cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) --cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) --db: VAESIMC Vdq,Wdq (66),(v1) --dc: VAESENC Vdq,Hdq,Wdq (66),(v1) --dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) --de: VAESDEC Vdq,Hdq,Wdq (66),(v1) --df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) --f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) --f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) --f2: ANDN Gy,By,Ey (v) --f3: Grp17 (1A) --f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) --f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) --f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) --EndTable -- --Table: 3-byte opcode 2 (0x0f 0x3a) --Referrer: 3-byte escape 2 --AVXcode: 3 --# 0x0f 0x3a 0x00-0xff --00: vpermq Vqq,Wqq,Ib (66),(v) --01: vpermpd Vqq,Wqq,Ib (66),(v) --02: vpblendd Vx,Hx,Wx,Ib (66),(v) --03: valignd/q Vx,Hx,Wx,Ib (66),(ev) --04: vpermilps Vx,Wx,Ib (66),(v) --05: vpermilpd Vx,Wx,Ib (66),(v) --06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) --07: --08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) --09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) --0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) --0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) --0c: vblendps Vx,Hx,Wx,Ib (66) --0d: vblendpd Vx,Hx,Wx,Ib (66) --0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) --0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) --14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) --15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) --16: vpextrd/q Ey,Vdq,Ib (66),(v1) --17: vextractps Ed,Vdq,Ib (66),(v1) --18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) --19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) --1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) --1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) --1d: vcvtps2ph Wx,Vx,Ib (66),(v) --1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) --1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) --20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) --21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) --22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) --23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) --25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) --26: vgetmantps/d Vx,Wx,Ib (66),(ev) --27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) --30: kshiftrb/w Vk,Uk,Ib (66),(v) --31: kshiftrd/q Vk,Uk,Ib (66),(v) --32: kshiftlb/w Vk,Uk,Ib (66),(v) --33: kshiftld/q Vk,Uk,Ib (66),(v) --38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) --39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) --3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) --3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) --3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) --3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) --40: vdpps Vx,Hx,Wx,Ib (66) --41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) --42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) --43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) --44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) --46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) --4a: vblendvps Vx,Hx,Wx,Lx (66),(v) --4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) --4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) --50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) --51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) --54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) --55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) --56: vreduceps/d Vx,Wx,Ib (66),(ev) --57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) --60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) --61: vpcmpestri Vdq,Wdq,Ib (66),(v1) --62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) --63: vpcmpistri Vdq,Wdq,Ib (66),(v1) --66: vfpclassps/d Vk,Wx,Ib (66),(ev) --67: vfpclassss/d Vk,Wx,Ib (66),(ev) --cc: sha1rnds4 Vdq,Wdq,Ib --df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) --f0: RORX Gy,Ey,Ib (F2),(v) --EndTable -- --GrpTable: Grp1 --0: ADD --1: OR --2: ADC --3: SBB --4: AND --5: SUB --6: XOR --7: CMP --EndTable -- --GrpTable: Grp1A --0: POP --EndTable -- --GrpTable: Grp2 --0: ROL --1: ROR --2: RCL --3: RCR --4: SHL/SAL --5: SHR --6: --7: SAR --EndTable -- --GrpTable: Grp3_1 --0: TEST Eb,Ib --1: --2: NOT Eb --3: NEG Eb --4: MUL AL,Eb --5: IMUL AL,Eb --6: DIV AL,Eb --7: IDIV AL,Eb --EndTable -- --GrpTable: Grp3_2 --0: TEST Ev,Iz --1: --2: NOT Ev --3: NEG Ev --4: MUL rAX,Ev --5: IMUL rAX,Ev --6: DIV rAX,Ev --7: IDIV rAX,Ev --EndTable -- --GrpTable: Grp4 --0: INC Eb --1: DEC Eb --EndTable -- --GrpTable: Grp5 --0: INC Ev --1: DEC Ev --# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). --2: CALLN Ev (f64) --3: CALLF Ep --4: JMPN Ev (f64) --5: JMPF Mp --6: PUSH Ev (d64) --7: --EndTable -- --GrpTable: Grp6 --0: SLDT Rv/Mw --1: STR Rv/Mw --2: LLDT Ew --3: LTR Ew --4: VERR Ew --5: VERW Ew --EndTable -- --GrpTable: Grp7 --0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) --1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) --2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) --3: LIDT Ms --4: SMSW Mw/Rv --5: rdpkru (110),(11B) | wrpkru (111),(11B) --6: LMSW Ew --7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) --EndTable -- --GrpTable: Grp8 --4: BT --5: BTS --6: BTR --7: BTC --EndTable -- --GrpTable: Grp9 --1: CMPXCHG8B/16B Mq/Mdq --3: xrstors --4: xsavec --5: xsaves --6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) --7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) --EndTable -- --GrpTable: Grp10 --EndTable -- --# Grp11A and Grp11B are expressed as Grp11 in Intel SDM --GrpTable: Grp11A --0: MOV Eb,Ib --7: XABORT Ib (000),(11B) --EndTable -- --GrpTable: Grp11B --0: MOV Eb,Iz --7: XBEGIN Jz (000),(11B) --EndTable -- --GrpTable: Grp12 --2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) --4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) --6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) --EndTable -- --GrpTable: Grp13 --0: vprord/q Hx,Wx,Ib (66),(ev) --1: vprold/q Hx,Wx,Ib (66),(ev) --2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) --4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) --6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) --EndTable -- --GrpTable: Grp14 --2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) --3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) --6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) --7: vpslldq Hx,Ux,Ib (66),(11B),(v1) --EndTable -- --GrpTable: Grp15 --0: fxsave | RDFSBASE Ry (F3),(11B) --1: fxstor | RDGSBASE Ry (F3),(11B) --2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) --3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) --4: XSAVE --5: XRSTOR | lfence (11B) --6: XSAVEOPT | clwb (66) | mfence (11B) --7: clflush | clflushopt (66) | sfence (11B) --EndTable -- --GrpTable: Grp16 --0: prefetch NTA --1: prefetch T0 --2: prefetch T1 --3: prefetch T2 --EndTable -- --GrpTable: Grp17 --1: BLSR By,Ey (v) --2: BLSMSK By,Ey (v) --3: BLSI By,Ey (v) --EndTable -- --GrpTable: Grp18 --1: vgatherpf0dps/d Wx (66),(ev) --2: vgatherpf1dps/d Wx (66),(ev) --5: vscatterpf0dps/d Wx (66),(ev) --6: vscatterpf1dps/d Wx (66),(ev) --EndTable -- --GrpTable: Grp19 --1: vgatherpf0qps/d Wx (66),(ev) --2: vgatherpf1qps/d Wx (66),(ev) --5: vscatterpf0qps/d Wx (66),(ev) --6: vscatterpf1qps/d Wx (66),(ev) --EndTable -- --# AMD's Prefetch Group --GrpTable: GrpP --0: PREFETCH --1: PREFETCHW --EndTable -- --GrpTable: GrpPDLK --0: MONTMUL --1: XSHA1 --2: XSHA2 --EndTable -- --GrpTable: GrpRNG --0: xstore-rng --1: xcrypt-ecb --2: xcrypt-cbc --4: xcrypt-cfb --5: xcrypt-ofb --EndTable -diff --git a/tools/objtool/arch/x86/lib/inat.c b/tools/objtool/arch/x86/lib/inat.c -new file mode 100644 -index 0000000..c1f01a8 ---- /dev/null -+++ b/tools/objtool/arch/x86/lib/inat.c -@@ -0,0 +1,97 @@ -+/* -+ * x86 instruction attribute tables -+ * -+ * Written by Masami Hiramatsu <mhiramat@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ */ -+#include <asm/insn.h> -+ -+/* Attribute tables are generated from opcode map */ -+#include "inat-tables.c" -+ -+/* Attribute search APIs */ -+insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) -+{ -+ return inat_primary_table[opcode]; -+} -+ -+int inat_get_last_prefix_id(insn_byte_t last_pfx) -+{ -+ insn_attr_t lpfx_attr; -+ -+ lpfx_attr = inat_get_opcode_attribute(last_pfx); -+ return inat_last_prefix_id(lpfx_attr); -+} -+ -+insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, -+ insn_attr_t esc_attr) -+{ -+ const insn_attr_t *table; -+ int n; -+ -+ n = inat_escape_id(esc_attr); -+ -+ table = inat_escape_tables[n][0]; -+ if (!table) -+ return 0; -+ if (inat_has_variant(table[opcode]) && lpfx_id) { -+ table = inat_escape_tables[n][lpfx_id]; -+ if (!table) -+ return 0; -+ } -+ return table[opcode]; -+} -+ -+insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, -+ insn_attr_t grp_attr) -+{ -+ const insn_attr_t *table; -+ int n; -+ -+ n = inat_group_id(grp_attr); -+ -+ table = inat_group_tables[n][0]; -+ if (!table) -+ return inat_group_common_attribute(grp_attr); -+ if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { -+ table = inat_group_tables[n][lpfx_id]; -+ if (!table) -+ return inat_group_common_attribute(grp_attr); -+ } -+ return table[X86_MODRM_REG(modrm)] | -+ inat_group_common_attribute(grp_attr); -+} -+ -+insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, -+ insn_byte_t vex_p) -+{ -+ const insn_attr_t *table; -+ if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) -+ return 0; -+ /* At first, this checks the master table */ -+ table = inat_avx_tables[vex_m][0]; -+ if (!table) -+ return 0; -+ if (!inat_is_group(table[opcode]) && vex_p) { -+ /* If this is not a group, get attribute directly */ -+ table = inat_avx_tables[vex_m][vex_p]; -+ if (!table) -+ return 0; -+ } -+ return table[opcode]; -+} -+ -diff --git a/tools/objtool/arch/x86/lib/insn.c b/tools/objtool/arch/x86/lib/insn.c -new file mode 100644 -index 0000000..1088eb8 ---- /dev/null -+++ b/tools/objtool/arch/x86/lib/insn.c -@@ -0,0 +1,606 @@ -+/* -+ * x86 instruction analysis -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -+ * -+ * Copyright (C) IBM Corporation, 2002, 2004, 2009 -+ */ -+ -+#ifdef __KERNEL__ -+#include <linux/string.h> -+#else -+#include <string.h> -+#endif -+#include <asm/inat.h> -+#include <asm/insn.h> -+ -+/* Verify next sizeof(t) bytes can be on the same instruction */ -+#define validate_next(t, insn, n) \ -+ ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) -+ -+#define __get_next(t, insn) \ -+ ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) -+ -+#define __peek_nbyte_next(t, insn, n) \ -+ ({ t r = *(t*)((insn)->next_byte + n); r; }) -+ -+#define get_next(t, insn) \ -+ ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) -+ -+#define peek_nbyte_next(t, insn, n) \ -+ ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) -+ -+#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) -+ -+/** -+ * insn_init() - initialize struct insn -+ * @insn: &struct insn to be initialized -+ * @kaddr: address (in kernel memory) of instruction (or copy thereof) -+ * @x86_64: !0 for 64-bit kernel or 64-bit app -+ */ -+void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) -+{ -+ /* -+ * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid -+ * even if the input buffer is long enough to hold them. -+ */ -+ if (buf_len > MAX_INSN_SIZE) -+ buf_len = MAX_INSN_SIZE; -+ -+ memset(insn, 0, sizeof(*insn)); -+ insn->kaddr = kaddr; -+ insn->end_kaddr = kaddr + buf_len; -+ insn->next_byte = kaddr; -+ insn->x86_64 = x86_64 ? 1 : 0; -+ insn->opnd_bytes = 4; -+ if (x86_64) -+ insn->addr_bytes = 8; -+ else -+ insn->addr_bytes = 4; -+} -+ -+/** -+ * insn_get_prefixes - scan x86 instruction prefix bytes -+ * @insn: &struct insn containing instruction -+ * -+ * Populates the @insn->prefixes bitmap, and updates @insn->next_byte -+ * to point to the (first) opcode. No effect if @insn->prefixes.got -+ * is already set. -+ */ -+void insn_get_prefixes(struct insn *insn) -+{ -+ struct insn_field *prefixes = &insn->prefixes; -+ insn_attr_t attr; -+ insn_byte_t b, lb; -+ int i, nb; -+ -+ if (prefixes->got) -+ return; -+ -+ nb = 0; -+ lb = 0; -+ b = peek_next(insn_byte_t, insn); -+ attr = inat_get_opcode_attribute(b); -+ while (inat_is_legacy_prefix(attr)) { -+ /* Skip if same prefix */ -+ for (i = 0; i < nb; i++) -+ if (prefixes->bytes[i] == b) -+ goto found; -+ if (nb == 4) -+ /* Invalid instruction */ -+ break; -+ prefixes->bytes[nb++] = b; -+ if (inat_is_address_size_prefix(attr)) { -+ /* address size switches 2/4 or 4/8 */ -+ if (insn->x86_64) -+ insn->addr_bytes ^= 12; -+ else -+ insn->addr_bytes ^= 6; -+ } else if (inat_is_operand_size_prefix(attr)) { -+ /* oprand size switches 2/4 */ -+ insn->opnd_bytes ^= 6; -+ } -+found: -+ prefixes->nbytes++; -+ insn->next_byte++; -+ lb = b; -+ b = peek_next(insn_byte_t, insn); -+ attr = inat_get_opcode_attribute(b); -+ } -+ /* Set the last prefix */ -+ if (lb && lb != insn->prefixes.bytes[3]) { -+ if (unlikely(insn->prefixes.bytes[3])) { -+ /* Swap the last prefix */ -+ b = insn->prefixes.bytes[3]; -+ for (i = 0; i < nb; i++) -+ if (prefixes->bytes[i] == lb) -+ prefixes->bytes[i] = b; -+ } -+ insn->prefixes.bytes[3] = lb; -+ } -+ -+ /* Decode REX prefix */ -+ if (insn->x86_64) { -+ b = peek_next(insn_byte_t, insn); -+ attr = inat_get_opcode_attribute(b); -+ if (inat_is_rex_prefix(attr)) { -+ insn->rex_prefix.value = b; -+ insn->rex_prefix.nbytes = 1; -+ insn->next_byte++; -+ if (X86_REX_W(b)) -+ /* REX.W overrides opnd_size */ -+ insn->opnd_bytes = 8; -+ } -+ } -+ insn->rex_prefix.got = 1; -+ -+ /* Decode VEX prefix */ -+ b = peek_next(insn_byte_t, insn); -+ attr = inat_get_opcode_attribute(b); -+ if (inat_is_vex_prefix(attr)) { -+ insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); -+ if (!insn->x86_64) { -+ /* -+ * In 32-bits mode, if the [7:6] bits (mod bits of -+ * ModRM) on the second byte are not 11b, it is -+ * LDS or LES or BOUND. -+ */ -+ if (X86_MODRM_MOD(b2) != 3) -+ goto vex_end; -+ } -+ insn->vex_prefix.bytes[0] = b; -+ insn->vex_prefix.bytes[1] = b2; -+ if (inat_is_evex_prefix(attr)) { -+ b2 = peek_nbyte_next(insn_byte_t, insn, 2); -+ insn->vex_prefix.bytes[2] = b2; -+ b2 = peek_nbyte_next(insn_byte_t, insn, 3); -+ insn->vex_prefix.bytes[3] = b2; -+ insn->vex_prefix.nbytes = 4; -+ insn->next_byte += 4; -+ if (insn->x86_64 && X86_VEX_W(b2)) -+ /* VEX.W overrides opnd_size */ -+ insn->opnd_bytes = 8; -+ } else if (inat_is_vex3_prefix(attr)) { -+ b2 = peek_nbyte_next(insn_byte_t, insn, 2); -+ insn->vex_prefix.bytes[2] = b2; -+ insn->vex_prefix.nbytes = 3; -+ insn->next_byte += 3; -+ if (insn->x86_64 && X86_VEX_W(b2)) -+ /* VEX.W overrides opnd_size */ -+ insn->opnd_bytes = 8; -+ } else { -+ /* -+ * For VEX2, fake VEX3-like byte#2. -+ * Makes it easier to decode vex.W, vex.vvvv, -+ * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. -+ */ -+ insn->vex_prefix.bytes[2] = b2 & 0x7f; -+ insn->vex_prefix.nbytes = 2; -+ insn->next_byte += 2; -+ } -+ } -+vex_end: -+ insn->vex_prefix.got = 1; -+ -+ prefixes->got = 1; -+ -+err_out: -+ return; -+} -+ -+/** -+ * insn_get_opcode - collect opcode(s) -+ * @insn: &struct insn containing instruction -+ * -+ * Populates @insn->opcode, updates @insn->next_byte to point past the -+ * opcode byte(s), and set @insn->attr (except for groups). -+ * If necessary, first collects any preceding (prefix) bytes. -+ * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got -+ * is already 1. -+ */ -+void insn_get_opcode(struct insn *insn) -+{ -+ struct insn_field *opcode = &insn->opcode; -+ insn_byte_t op; -+ int pfx_id; -+ if (opcode->got) -+ return; -+ if (!insn->prefixes.got) -+ insn_get_prefixes(insn); -+ -+ /* Get first opcode */ -+ op = get_next(insn_byte_t, insn); -+ opcode->bytes[0] = op; -+ opcode->nbytes = 1; -+ -+ /* Check if there is VEX prefix or not */ -+ if (insn_is_avx(insn)) { -+ insn_byte_t m, p; -+ m = insn_vex_m_bits(insn); -+ p = insn_vex_p_bits(insn); -+ insn->attr = inat_get_avx_attribute(op, m, p); -+ if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || -+ (!inat_accept_vex(insn->attr) && -+ !inat_is_group(insn->attr))) -+ insn->attr = 0; /* This instruction is bad */ -+ goto end; /* VEX has only 1 byte for opcode */ -+ } -+ -+ insn->attr = inat_get_opcode_attribute(op); -+ while (inat_is_escape(insn->attr)) { -+ /* Get escaped opcode */ -+ op = get_next(insn_byte_t, insn); -+ opcode->bytes[opcode->nbytes++] = op; -+ pfx_id = insn_last_prefix_id(insn); -+ insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); -+ } -+ if (inat_must_vex(insn->attr)) -+ insn->attr = 0; /* This instruction is bad */ -+end: -+ opcode->got = 1; -+ -+err_out: -+ return; -+} -+ -+/** -+ * insn_get_modrm - collect ModRM byte, if any -+ * @insn: &struct insn containing instruction -+ * -+ * Populates @insn->modrm and updates @insn->next_byte to point past the -+ * ModRM byte, if any. If necessary, first collects the preceding bytes -+ * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. -+ */ -+void insn_get_modrm(struct insn *insn) -+{ -+ struct insn_field *modrm = &insn->modrm; -+ insn_byte_t pfx_id, mod; -+ if (modrm->got) -+ return; -+ if (!insn->opcode.got) -+ insn_get_opcode(insn); -+ -+ if (inat_has_modrm(insn->attr)) { -+ mod = get_next(insn_byte_t, insn); -+ modrm->value = mod; -+ modrm->nbytes = 1; -+ if (inat_is_group(insn->attr)) { -+ pfx_id = insn_last_prefix_id(insn); -+ insn->attr = inat_get_group_attribute(mod, pfx_id, -+ insn->attr); -+ if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) -+ insn->attr = 0; /* This is bad */ -+ } -+ } -+ -+ if (insn->x86_64 && inat_is_force64(insn->attr)) -+ insn->opnd_bytes = 8; -+ modrm->got = 1; -+ -+err_out: -+ return; -+} -+ -+ -+/** -+ * insn_rip_relative() - Does instruction use RIP-relative addressing mode? -+ * @insn: &struct insn containing instruction -+ * -+ * If necessary, first collects the instruction up to and including the -+ * ModRM byte. No effect if @insn->x86_64 is 0. -+ */ -+int insn_rip_relative(struct insn *insn) -+{ -+ struct insn_field *modrm = &insn->modrm; -+ -+ if (!insn->x86_64) -+ return 0; -+ if (!modrm->got) -+ insn_get_modrm(insn); -+ /* -+ * For rip-relative instructions, the mod field (top 2 bits) -+ * is zero and the r/m field (bottom 3 bits) is 0x5. -+ */ -+ return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); -+} -+ -+/** -+ * insn_get_sib() - Get the SIB byte of instruction -+ * @insn: &struct insn containing instruction -+ * -+ * If necessary, first collects the instruction up to and including the -+ * ModRM byte. -+ */ -+void insn_get_sib(struct insn *insn) -+{ -+ insn_byte_t modrm; -+ -+ if (insn->sib.got) -+ return; -+ if (!insn->modrm.got) -+ insn_get_modrm(insn); -+ if (insn->modrm.nbytes) { -+ modrm = (insn_byte_t)insn->modrm.value; -+ if (insn->addr_bytes != 2 && -+ X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { -+ insn->sib.value = get_next(insn_byte_t, insn); -+ insn->sib.nbytes = 1; -+ } -+ } -+ insn->sib.got = 1; -+ -+err_out: -+ return; -+} -+ -+ -+/** -+ * insn_get_displacement() - Get the displacement of instruction -+ * @insn: &struct insn containing instruction -+ * -+ * If necessary, first collects the instruction up to and including the -+ * SIB byte. -+ * Displacement value is sign-expanded. -+ */ -+void insn_get_displacement(struct insn *insn) -+{ -+ insn_byte_t mod, rm, base; -+ -+ if (insn->displacement.got) -+ return; -+ if (!insn->sib.got) -+ insn_get_sib(insn); -+ if (insn->modrm.nbytes) { -+ /* -+ * Interpreting the modrm byte: -+ * mod = 00 - no displacement fields (exceptions below) -+ * mod = 01 - 1-byte displacement field -+ * mod = 10 - displacement field is 4 bytes, or 2 bytes if -+ * address size = 2 (0x67 prefix in 32-bit mode) -+ * mod = 11 - no memory operand -+ * -+ * If address size = 2... -+ * mod = 00, r/m = 110 - displacement field is 2 bytes -+ * -+ * If address size != 2... -+ * mod != 11, r/m = 100 - SIB byte exists -+ * mod = 00, SIB base = 101 - displacement field is 4 bytes -+ * mod = 00, r/m = 101 - rip-relative addressing, displacement -+ * field is 4 bytes -+ */ -+ mod = X86_MODRM_MOD(insn->modrm.value); -+ rm = X86_MODRM_RM(insn->modrm.value); -+ base = X86_SIB_BASE(insn->sib.value); -+ if (mod == 3) -+ goto out; -+ if (mod == 1) { -+ insn->displacement.value = get_next(signed char, insn); -+ insn->displacement.nbytes = 1; -+ } else if (insn->addr_bytes == 2) { -+ if ((mod == 0 && rm == 6) || mod == 2) { -+ insn->displacement.value = -+ get_next(short, insn); -+ insn->displacement.nbytes = 2; -+ } -+ } else { -+ if ((mod == 0 && rm == 5) || mod == 2 || -+ (mod == 0 && base == 5)) { -+ insn->displacement.value = get_next(int, insn); -+ insn->displacement.nbytes = 4; -+ } -+ } -+ } -+out: -+ insn->displacement.got = 1; -+ -+err_out: -+ return; -+} -+ -+/* Decode moffset16/32/64. Return 0 if failed */ -+static int __get_moffset(struct insn *insn) -+{ -+ switch (insn->addr_bytes) { -+ case 2: -+ insn->moffset1.value = get_next(short, insn); -+ insn->moffset1.nbytes = 2; -+ break; -+ case 4: -+ insn->moffset1.value = get_next(int, insn); -+ insn->moffset1.nbytes = 4; -+ break; -+ case 8: -+ insn->moffset1.value = get_next(int, insn); -+ insn->moffset1.nbytes = 4; -+ insn->moffset2.value = get_next(int, insn); -+ insn->moffset2.nbytes = 4; -+ break; -+ default: /* opnd_bytes must be modified manually */ -+ goto err_out; -+ } -+ insn->moffset1.got = insn->moffset2.got = 1; -+ -+ return 1; -+ -+err_out: -+ return 0; -+} -+ -+/* Decode imm v32(Iz). Return 0 if failed */ -+static int __get_immv32(struct insn *insn) -+{ -+ switch (insn->opnd_bytes) { -+ case 2: -+ insn->immediate.value = get_next(short, insn); -+ insn->immediate.nbytes = 2; -+ break; -+ case 4: -+ case 8: -+ insn->immediate.value = get_next(int, insn); -+ insn->immediate.nbytes = 4; -+ break; -+ default: /* opnd_bytes must be modified manually */ -+ goto err_out; -+ } -+ -+ return 1; -+ -+err_out: -+ return 0; -+} -+ -+/* Decode imm v64(Iv/Ov), Return 0 if failed */ -+static int __get_immv(struct insn *insn) -+{ -+ switch (insn->opnd_bytes) { -+ case 2: -+ insn->immediate1.value = get_next(short, insn); -+ insn->immediate1.nbytes = 2; -+ break; -+ case 4: -+ insn->immediate1.value = get_next(int, insn); -+ insn->immediate1.nbytes = 4; -+ break; -+ case 8: -+ insn->immediate1.value = get_next(int, insn); -+ insn->immediate1.nbytes = 4; -+ insn->immediate2.value = get_next(int, insn); -+ insn->immediate2.nbytes = 4; -+ break; -+ default: /* opnd_bytes must be modified manually */ -+ goto err_out; -+ } -+ insn->immediate1.got = insn->immediate2.got = 1; -+ -+ return 1; -+err_out: -+ return 0; -+} -+ -+/* Decode ptr16:16/32(Ap) */ -+static int __get_immptr(struct insn *insn) -+{ -+ switch (insn->opnd_bytes) { -+ case 2: -+ insn->immediate1.value = get_next(short, insn); -+ insn->immediate1.nbytes = 2; -+ break; -+ case 4: -+ insn->immediate1.value = get_next(int, insn); -+ insn->immediate1.nbytes = 4; -+ break; -+ case 8: -+ /* ptr16:64 is not exist (no segment) */ -+ return 0; -+ default: /* opnd_bytes must be modified manually */ -+ goto err_out; -+ } -+ insn->immediate2.value = get_next(unsigned short, insn); -+ insn->immediate2.nbytes = 2; -+ insn->immediate1.got = insn->immediate2.got = 1; -+ -+ return 1; -+err_out: -+ return 0; -+} -+ -+/** -+ * insn_get_immediate() - Get the immediates of instruction -+ * @insn: &struct insn containing instruction -+ * -+ * If necessary, first collects the instruction up to and including the -+ * displacement bytes. -+ * Basically, most of immediates are sign-expanded. Unsigned-value can be -+ * get by bit masking with ((1 << (nbytes * 8)) - 1) -+ */ -+void insn_get_immediate(struct insn *insn) -+{ -+ if (insn->immediate.got) -+ return; -+ if (!insn->displacement.got) -+ insn_get_displacement(insn); -+ -+ if (inat_has_moffset(insn->attr)) { -+ if (!__get_moffset(insn)) -+ goto err_out; -+ goto done; -+ } -+ -+ if (!inat_has_immediate(insn->attr)) -+ /* no immediates */ -+ goto done; -+ -+ switch (inat_immediate_size(insn->attr)) { -+ case INAT_IMM_BYTE: -+ insn->immediate.value = get_next(signed char, insn); -+ insn->immediate.nbytes = 1; -+ break; -+ case INAT_IMM_WORD: -+ insn->immediate.value = get_next(short, insn); -+ insn->immediate.nbytes = 2; -+ break; -+ case INAT_IMM_DWORD: -+ insn->immediate.value = get_next(int, insn); -+ insn->immediate.nbytes = 4; -+ break; -+ case INAT_IMM_QWORD: -+ insn->immediate1.value = get_next(int, insn); -+ insn->immediate1.nbytes = 4; -+ insn->immediate2.value = get_next(int, insn); -+ insn->immediate2.nbytes = 4; -+ break; -+ case INAT_IMM_PTR: -+ if (!__get_immptr(insn)) -+ goto err_out; -+ break; -+ case INAT_IMM_VWORD32: -+ if (!__get_immv32(insn)) -+ goto err_out; -+ break; -+ case INAT_IMM_VWORD: -+ if (!__get_immv(insn)) -+ goto err_out; -+ break; -+ default: -+ /* Here, insn must have an immediate, but failed */ -+ goto err_out; -+ } -+ if (inat_has_second_immediate(insn->attr)) { -+ insn->immediate2.value = get_next(signed char, insn); -+ insn->immediate2.nbytes = 1; -+ } -+done: -+ insn->immediate.got = 1; -+ -+err_out: -+ return; -+} -+ -+/** -+ * insn_get_length() - Get the length of instruction -+ * @insn: &struct insn containing instruction -+ * -+ * If necessary, first collects the instruction up to and including the -+ * immediates bytes. -+ */ -+void insn_get_length(struct insn *insn) -+{ -+ if (insn->length) -+ return; -+ if (!insn->immediate.got) -+ insn_get_immediate(insn); -+ insn->length = (unsigned char)((unsigned long)insn->next_byte -+ - (unsigned long)insn->kaddr); -+} -diff --git a/tools/objtool/arch/x86/lib/x86-opcode-map.txt b/tools/objtool/arch/x86/lib/x86-opcode-map.txt -new file mode 100644 -index 0000000..aa2270d ---- /dev/null -+++ b/tools/objtool/arch/x86/lib/x86-opcode-map.txt -@@ -0,0 +1,1072 @@ -+# x86 Opcode Maps -+# -+# This is (mostly) based on following documentations. -+# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C -+# (#326018-047US, June 2013) -+# -+#<Opcode maps> -+# Table: table-name -+# Referrer: escaped-name -+# AVXcode: avx-code -+# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] -+# (or) -+# opcode: escape # escaped-name -+# EndTable -+# -+# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix -+# mnemonics that begin with lowercase 'k' accept a VEX prefix -+# -+#<group maps> -+# GrpTable: GrpXXX -+# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] -+# EndTable -+# -+# AVX Superscripts -+# (ev): this opcode requires EVEX prefix. -+# (evo): this opcode is changed by EVEX prefix (EVEX opcode) -+# (v): this opcode requires VEX prefix. -+# (v1): this opcode only supports 128bit VEX. -+# -+# Last Prefix Superscripts -+# - (66): the last prefix is 0x66 -+# - (F3): the last prefix is 0xF3 -+# - (F2): the last prefix is 0xF2 -+# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) -+# - (66&F2): Both 0x66 and 0xF2 prefixes are specified. -+ -+Table: one byte opcode -+Referrer: -+AVXcode: -+# 0x00 - 0x0f -+00: ADD Eb,Gb -+01: ADD Ev,Gv -+02: ADD Gb,Eb -+03: ADD Gv,Ev -+04: ADD AL,Ib -+05: ADD rAX,Iz -+06: PUSH ES (i64) -+07: POP ES (i64) -+08: OR Eb,Gb -+09: OR Ev,Gv -+0a: OR Gb,Eb -+0b: OR Gv,Ev -+0c: OR AL,Ib -+0d: OR rAX,Iz -+0e: PUSH CS (i64) -+0f: escape # 2-byte escape -+# 0x10 - 0x1f -+10: ADC Eb,Gb -+11: ADC Ev,Gv -+12: ADC Gb,Eb -+13: ADC Gv,Ev -+14: ADC AL,Ib -+15: ADC rAX,Iz -+16: PUSH SS (i64) -+17: POP SS (i64) -+18: SBB Eb,Gb -+19: SBB Ev,Gv -+1a: SBB Gb,Eb -+1b: SBB Gv,Ev -+1c: SBB AL,Ib -+1d: SBB rAX,Iz -+1e: PUSH DS (i64) -+1f: POP DS (i64) -+# 0x20 - 0x2f -+20: AND Eb,Gb -+21: AND Ev,Gv -+22: AND Gb,Eb -+23: AND Gv,Ev -+24: AND AL,Ib -+25: AND rAx,Iz -+26: SEG=ES (Prefix) -+27: DAA (i64) -+28: SUB Eb,Gb -+29: SUB Ev,Gv -+2a: SUB Gb,Eb -+2b: SUB Gv,Ev -+2c: SUB AL,Ib -+2d: SUB rAX,Iz -+2e: SEG=CS (Prefix) -+2f: DAS (i64) -+# 0x30 - 0x3f -+30: XOR Eb,Gb -+31: XOR Ev,Gv -+32: XOR Gb,Eb -+33: XOR Gv,Ev -+34: XOR AL,Ib -+35: XOR rAX,Iz -+36: SEG=SS (Prefix) -+37: AAA (i64) -+38: CMP Eb,Gb -+39: CMP Ev,Gv -+3a: CMP Gb,Eb -+3b: CMP Gv,Ev -+3c: CMP AL,Ib -+3d: CMP rAX,Iz -+3e: SEG=DS (Prefix) -+3f: AAS (i64) -+# 0x40 - 0x4f -+40: INC eAX (i64) | REX (o64) -+41: INC eCX (i64) | REX.B (o64) -+42: INC eDX (i64) | REX.X (o64) -+43: INC eBX (i64) | REX.XB (o64) -+44: INC eSP (i64) | REX.R (o64) -+45: INC eBP (i64) | REX.RB (o64) -+46: INC eSI (i64) | REX.RX (o64) -+47: INC eDI (i64) | REX.RXB (o64) -+48: DEC eAX (i64) | REX.W (o64) -+49: DEC eCX (i64) | REX.WB (o64) -+4a: DEC eDX (i64) | REX.WX (o64) -+4b: DEC eBX (i64) | REX.WXB (o64) -+4c: DEC eSP (i64) | REX.WR (o64) -+4d: DEC eBP (i64) | REX.WRB (o64) -+4e: DEC eSI (i64) | REX.WRX (o64) -+4f: DEC eDI (i64) | REX.WRXB (o64) -+# 0x50 - 0x5f -+50: PUSH rAX/r8 (d64) -+51: PUSH rCX/r9 (d64) -+52: PUSH rDX/r10 (d64) -+53: PUSH rBX/r11 (d64) -+54: PUSH rSP/r12 (d64) -+55: PUSH rBP/r13 (d64) -+56: PUSH rSI/r14 (d64) -+57: PUSH rDI/r15 (d64) -+58: POP rAX/r8 (d64) -+59: POP rCX/r9 (d64) -+5a: POP rDX/r10 (d64) -+5b: POP rBX/r11 (d64) -+5c: POP rSP/r12 (d64) -+5d: POP rBP/r13 (d64) -+5e: POP rSI/r14 (d64) -+5f: POP rDI/r15 (d64) -+# 0x60 - 0x6f -+60: PUSHA/PUSHAD (i64) -+61: POPA/POPAD (i64) -+62: BOUND Gv,Ma (i64) | EVEX (Prefix) -+63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) -+64: SEG=FS (Prefix) -+65: SEG=GS (Prefix) -+66: Operand-Size (Prefix) -+67: Address-Size (Prefix) -+68: PUSH Iz (d64) -+69: IMUL Gv,Ev,Iz -+6a: PUSH Ib (d64) -+6b: IMUL Gv,Ev,Ib -+6c: INS/INSB Yb,DX -+6d: INS/INSW/INSD Yz,DX -+6e: OUTS/OUTSB DX,Xb -+6f: OUTS/OUTSW/OUTSD DX,Xz -+# 0x70 - 0x7f -+70: JO Jb -+71: JNO Jb -+72: JB/JNAE/JC Jb -+73: JNB/JAE/JNC Jb -+74: JZ/JE Jb -+75: JNZ/JNE Jb -+76: JBE/JNA Jb -+77: JNBE/JA Jb -+78: JS Jb -+79: JNS Jb -+7a: JP/JPE Jb -+7b: JNP/JPO Jb -+7c: JL/JNGE Jb -+7d: JNL/JGE Jb -+7e: JLE/JNG Jb -+7f: JNLE/JG Jb -+# 0x80 - 0x8f -+80: Grp1 Eb,Ib (1A) -+81: Grp1 Ev,Iz (1A) -+82: Grp1 Eb,Ib (1A),(i64) -+83: Grp1 Ev,Ib (1A) -+84: TEST Eb,Gb -+85: TEST Ev,Gv -+86: XCHG Eb,Gb -+87: XCHG Ev,Gv -+88: MOV Eb,Gb -+89: MOV Ev,Gv -+8a: MOV Gb,Eb -+8b: MOV Gv,Ev -+8c: MOV Ev,Sw -+8d: LEA Gv,M -+8e: MOV Sw,Ew -+8f: Grp1A (1A) | POP Ev (d64) -+# 0x90 - 0x9f -+90: NOP | PAUSE (F3) | XCHG r8,rAX -+91: XCHG rCX/r9,rAX -+92: XCHG rDX/r10,rAX -+93: XCHG rBX/r11,rAX -+94: XCHG rSP/r12,rAX -+95: XCHG rBP/r13,rAX -+96: XCHG rSI/r14,rAX -+97: XCHG rDI/r15,rAX -+98: CBW/CWDE/CDQE -+99: CWD/CDQ/CQO -+9a: CALLF Ap (i64) -+9b: FWAIT/WAIT -+9c: PUSHF/D/Q Fv (d64) -+9d: POPF/D/Q Fv (d64) -+9e: SAHF -+9f: LAHF -+# 0xa0 - 0xaf -+a0: MOV AL,Ob -+a1: MOV rAX,Ov -+a2: MOV Ob,AL -+a3: MOV Ov,rAX -+a4: MOVS/B Yb,Xb -+a5: MOVS/W/D/Q Yv,Xv -+a6: CMPS/B Xb,Yb -+a7: CMPS/W/D Xv,Yv -+a8: TEST AL,Ib -+a9: TEST rAX,Iz -+aa: STOS/B Yb,AL -+ab: STOS/W/D/Q Yv,rAX -+ac: LODS/B AL,Xb -+ad: LODS/W/D/Q rAX,Xv -+ae: SCAS/B AL,Yb -+# Note: The May 2011 Intel manual shows Xv for the second parameter of the -+# next instruction but Yv is correct -+af: SCAS/W/D/Q rAX,Yv -+# 0xb0 - 0xbf -+b0: MOV AL/R8L,Ib -+b1: MOV CL/R9L,Ib -+b2: MOV DL/R10L,Ib -+b3: MOV BL/R11L,Ib -+b4: MOV AH/R12L,Ib -+b5: MOV CH/R13L,Ib -+b6: MOV DH/R14L,Ib -+b7: MOV BH/R15L,Ib -+b8: MOV rAX/r8,Iv -+b9: MOV rCX/r9,Iv -+ba: MOV rDX/r10,Iv -+bb: MOV rBX/r11,Iv -+bc: MOV rSP/r12,Iv -+bd: MOV rBP/r13,Iv -+be: MOV rSI/r14,Iv -+bf: MOV rDI/r15,Iv -+# 0xc0 - 0xcf -+c0: Grp2 Eb,Ib (1A) -+c1: Grp2 Ev,Ib (1A) -+c2: RETN Iw (f64) -+c3: RETN -+c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) -+c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) -+c6: Grp11A Eb,Ib (1A) -+c7: Grp11B Ev,Iz (1A) -+c8: ENTER Iw,Ib -+c9: LEAVE (d64) -+ca: RETF Iw -+cb: RETF -+cc: INT3 -+cd: INT Ib -+ce: INTO (i64) -+cf: IRET/D/Q -+# 0xd0 - 0xdf -+d0: Grp2 Eb,1 (1A) -+d1: Grp2 Ev,1 (1A) -+d2: Grp2 Eb,CL (1A) -+d3: Grp2 Ev,CL (1A) -+d4: AAM Ib (i64) -+d5: AAD Ib (i64) -+d6: -+d7: XLAT/XLATB -+d8: ESC -+d9: ESC -+da: ESC -+db: ESC -+dc: ESC -+dd: ESC -+de: ESC -+df: ESC -+# 0xe0 - 0xef -+# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix -+# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation -+# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD. -+e0: LOOPNE/LOOPNZ Jb (f64) -+e1: LOOPE/LOOPZ Jb (f64) -+e2: LOOP Jb (f64) -+e3: JrCXZ Jb (f64) -+e4: IN AL,Ib -+e5: IN eAX,Ib -+e6: OUT Ib,AL -+e7: OUT Ib,eAX -+# With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset -+# in "near" jumps and calls is 16-bit. For CALL, -+# push of return address is 16-bit wide, RSP is decremented by 2 -+# but is not truncated to 16 bits, unlike RIP. -+e8: CALL Jz (f64) -+e9: JMP-near Jz (f64) -+ea: JMP-far Ap (i64) -+eb: JMP-short Jb (f64) -+ec: IN AL,DX -+ed: IN eAX,DX -+ee: OUT DX,AL -+ef: OUT DX,eAX -+# 0xf0 - 0xff -+f0: LOCK (Prefix) -+f1: -+f2: REPNE (Prefix) | XACQUIRE (Prefix) -+f3: REP/REPE (Prefix) | XRELEASE (Prefix) -+f4: HLT -+f5: CMC -+f6: Grp3_1 Eb (1A) -+f7: Grp3_2 Ev (1A) -+f8: CLC -+f9: STC -+fa: CLI -+fb: STI -+fc: CLD -+fd: STD -+fe: Grp4 (1A) -+ff: Grp5 (1A) -+EndTable -+ -+Table: 2-byte opcode (0x0f) -+Referrer: 2-byte escape -+AVXcode: 1 -+# 0x0f 0x00-0x0f -+00: Grp6 (1A) -+01: Grp7 (1A) -+02: LAR Gv,Ew -+03: LSL Gv,Ew -+04: -+05: SYSCALL (o64) -+06: CLTS -+07: SYSRET (o64) -+08: INVD -+09: WBINVD -+0a: -+0b: UD2 (1B) -+0c: -+# AMD's prefetch group. Intel supports prefetchw(/1) only. -+0d: GrpP -+0e: FEMMS -+# 3DNow! uses the last imm byte as opcode extension. -+0f: 3DNow! Pq,Qq,Ib -+# 0x0f 0x10-0x1f -+# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands -+# but it actually has operands. And also, vmovss and vmovsd only accept 128bit. -+# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. -+# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming -+# Reference A.1 -+10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) -+11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) -+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) -+13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) -+14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) -+15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) -+16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) -+17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) -+18: Grp16 (1A) -+19: -+# Intel SDM opcode map does not list MPX instructions. For now using Gv for -+# bnd registers and Ev for everything else is OK because the instruction -+# decoder does not use the information except as an indication that there is -+# a ModR/M byte. -+1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev -+1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv -+1c: -+1d: -+1e: -+1f: NOP Ev -+# 0x0f 0x20-0x2f -+20: MOV Rd,Cd -+21: MOV Rd,Dd -+22: MOV Cd,Rd -+23: MOV Dd,Rd -+24: -+25: -+26: -+27: -+28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) -+29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) -+2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) -+2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) -+2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) -+2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) -+2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) -+2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) -+# 0x0f 0x30-0x3f -+30: WRMSR -+31: RDTSC -+32: RDMSR -+33: RDPMC -+34: SYSENTER -+35: SYSEXIT -+36: -+37: GETSEC -+38: escape # 3-byte escape 1 -+39: -+3a: escape # 3-byte escape 2 -+3b: -+3c: -+3d: -+3e: -+3f: -+# 0x0f 0x40-0x4f -+40: CMOVO Gv,Ev -+41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) -+42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) -+43: CMOVAE/NB/NC Gv,Ev -+44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) -+45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) -+46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) -+47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) -+48: CMOVS Gv,Ev -+49: CMOVNS Gv,Ev -+4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) -+4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk -+4c: CMOVL/NGE Gv,Ev -+4d: CMOVNL/GE Gv,Ev -+4e: CMOVLE/NG Gv,Ev -+4f: CMOVNLE/G Gv,Ev -+# 0x0f 0x50-0x5f -+50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) -+51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) -+52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) -+53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) -+54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) -+55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) -+56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) -+57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) -+58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) -+59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) -+5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) -+5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) -+5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) -+5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) -+5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) -+5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) -+# 0x0f 0x60-0x6f -+60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) -+61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) -+62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) -+63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) -+64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) -+65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) -+66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) -+67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) -+68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) -+69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) -+6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) -+6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) -+6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) -+6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) -+6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) -+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) -+# 0x0f 0x70-0x7f -+70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) -+71: Grp12 (1A) -+72: Grp13 (1A) -+73: Grp14 (1A) -+74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) -+75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) -+76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) -+# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. -+77: emms | vzeroupper | vzeroall -+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) -+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) -+7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) -+7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) -+7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) -+7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) -+7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) -+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) -+# 0x0f 0x80-0x8f -+# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). -+80: JO Jz (f64) -+81: JNO Jz (f64) -+82: JB/JC/JNAE Jz (f64) -+83: JAE/JNB/JNC Jz (f64) -+84: JE/JZ Jz (f64) -+85: JNE/JNZ Jz (f64) -+86: JBE/JNA Jz (f64) -+87: JA/JNBE Jz (f64) -+88: JS Jz (f64) -+89: JNS Jz (f64) -+8a: JP/JPE Jz (f64) -+8b: JNP/JPO Jz (f64) -+8c: JL/JNGE Jz (f64) -+8d: JNL/JGE Jz (f64) -+8e: JLE/JNG Jz (f64) -+8f: JNLE/JG Jz (f64) -+# 0x0f 0x90-0x9f -+90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) -+91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) -+92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) -+93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) -+94: SETE/Z Eb -+95: SETNE/NZ Eb -+96: SETBE/NA Eb -+97: SETA/NBE Eb -+98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) -+99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) -+9a: SETP/PE Eb -+9b: SETNP/PO Eb -+9c: SETL/NGE Eb -+9d: SETNL/GE Eb -+9e: SETLE/NG Eb -+9f: SETNLE/G Eb -+# 0x0f 0xa0-0xaf -+a0: PUSH FS (d64) -+a1: POP FS (d64) -+a2: CPUID -+a3: BT Ev,Gv -+a4: SHLD Ev,Gv,Ib -+a5: SHLD Ev,Gv,CL -+a6: GrpPDLK -+a7: GrpRNG -+a8: PUSH GS (d64) -+a9: POP GS (d64) -+aa: RSM -+ab: BTS Ev,Gv -+ac: SHRD Ev,Gv,Ib -+ad: SHRD Ev,Gv,CL -+ae: Grp15 (1A),(1C) -+af: IMUL Gv,Ev -+# 0x0f 0xb0-0xbf -+b0: CMPXCHG Eb,Gb -+b1: CMPXCHG Ev,Gv -+b2: LSS Gv,Mp -+b3: BTR Ev,Gv -+b4: LFS Gv,Mp -+b5: LGS Gv,Mp -+b6: MOVZX Gv,Eb -+b7: MOVZX Gv,Ew -+b8: JMPE (!F3) | POPCNT Gv,Ev (F3) -+b9: Grp10 (1A) -+ba: Grp8 Ev,Ib (1A) -+bb: BTC Ev,Gv -+bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) -+bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) -+be: MOVSX Gv,Eb -+bf: MOVSX Gv,Ew -+# 0x0f 0xc0-0xcf -+c0: XADD Eb,Gb -+c1: XADD Ev,Gv -+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) -+c3: movnti My,Gy -+c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) -+c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) -+c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) -+c7: Grp9 (1A) -+c8: BSWAP RAX/EAX/R8/R8D -+c9: BSWAP RCX/ECX/R9/R9D -+ca: BSWAP RDX/EDX/R10/R10D -+cb: BSWAP RBX/EBX/R11/R11D -+cc: BSWAP RSP/ESP/R12/R12D -+cd: BSWAP RBP/EBP/R13/R13D -+ce: BSWAP RSI/ESI/R14/R14D -+cf: BSWAP RDI/EDI/R15/R15D -+# 0x0f 0xd0-0xdf -+d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) -+d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) -+d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) -+d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) -+d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) -+d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) -+d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) -+d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) -+d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) -+d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) -+da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) -+db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) -+dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) -+dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) -+de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) -+df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) -+# 0x0f 0xe0-0xef -+e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) -+e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) -+e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) -+e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) -+e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) -+e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) -+e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) -+e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) -+e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) -+e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) -+ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) -+eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) -+ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) -+ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) -+ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) -+ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) -+# 0x0f 0xf0-0xff -+f0: vlddqu Vx,Mx (F2) -+f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) -+f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) -+f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) -+f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) -+f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) -+f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) -+f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) -+f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) -+f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) -+fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) -+fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) -+fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) -+fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) -+fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) -+ff: UD0 -+EndTable -+ -+Table: 3-byte opcode 1 (0x0f 0x38) -+Referrer: 3-byte escape 1 -+AVXcode: 2 -+# 0x0f 0x38 0x00-0x0f -+00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) -+01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) -+02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) -+03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) -+04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) -+05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) -+06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) -+07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) -+08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) -+09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) -+0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) -+0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) -+0c: vpermilps Vx,Hx,Wx (66),(v) -+0d: vpermilpd Vx,Hx,Wx (66),(v) -+0e: vtestps Vx,Wx (66),(v) -+0f: vtestpd Vx,Wx (66),(v) -+# 0x0f 0x38 0x10-0x1f -+10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) -+11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) -+12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) -+13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) -+14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) -+15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) -+16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) -+17: vptest Vx,Wx (66) -+18: vbroadcastss Vx,Wd (66),(v) -+19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) -+1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) -+1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) -+1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) -+1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) -+1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) -+1f: vpabsq Vx,Wx (66),(ev) -+# 0x0f 0x38 0x20-0x2f -+20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) -+21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) -+22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) -+23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) -+24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) -+25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) -+26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) -+27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) -+28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) -+29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) -+2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) -+2b: vpackusdw Vx,Hx,Wx (66),(v1) -+2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) -+2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) -+2e: vmaskmovps Mx,Hx,Vx (66),(v) -+2f: vmaskmovpd Mx,Hx,Vx (66),(v) -+# 0x0f 0x38 0x30-0x3f -+30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) -+31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) -+32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) -+33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) -+34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) -+35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) -+36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) -+37: vpcmpgtq Vx,Hx,Wx (66),(v1) -+38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) -+39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) -+3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) -+3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) -+3c: vpmaxsb Vx,Hx,Wx (66),(v1) -+3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) -+3e: vpmaxuw Vx,Hx,Wx (66),(v1) -+3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) -+# 0x0f 0x38 0x40-0x8f -+40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) -+41: vphminposuw Vdq,Wdq (66),(v1) -+42: vgetexpps/d Vx,Wx (66),(ev) -+43: vgetexpss/d Vx,Hx,Wx (66),(ev) -+44: vplzcntd/q Vx,Wx (66),(ev) -+45: vpsrlvd/q Vx,Hx,Wx (66),(v) -+46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) -+47: vpsllvd/q Vx,Hx,Wx (66),(v) -+# Skip 0x48-0x4b -+4c: vrcp14ps/d Vpd,Wpd (66),(ev) -+4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) -+4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) -+4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) -+# Skip 0x50-0x57 -+58: vpbroadcastd Vx,Wx (66),(v) -+59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) -+5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) -+5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) -+# Skip 0x5c-0x63 -+64: vpblendmd/q Vx,Hx,Wx (66),(ev) -+65: vblendmps/d Vx,Hx,Wx (66),(ev) -+66: vpblendmb/w Vx,Hx,Wx (66),(ev) -+# Skip 0x67-0x74 -+75: vpermi2b/w Vx,Hx,Wx (66),(ev) -+76: vpermi2d/q Vx,Hx,Wx (66),(ev) -+77: vpermi2ps/d Vx,Hx,Wx (66),(ev) -+78: vpbroadcastb Vx,Wx (66),(v) -+79: vpbroadcastw Vx,Wx (66),(v) -+7a: vpbroadcastb Vx,Rv (66),(ev) -+7b: vpbroadcastw Vx,Rv (66),(ev) -+7c: vpbroadcastd/q Vx,Rv (66),(ev) -+7d: vpermt2b/w Vx,Hx,Wx (66),(ev) -+7e: vpermt2d/q Vx,Hx,Wx (66),(ev) -+7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) -+80: INVEPT Gy,Mdq (66) -+81: INVVPID Gy,Mdq (66) -+82: INVPCID Gy,Mdq (66) -+83: vpmultishiftqb Vx,Hx,Wx (66),(ev) -+88: vexpandps/d Vpd,Wpd (66),(ev) -+89: vpexpandd/q Vx,Wx (66),(ev) -+8a: vcompressps/d Wx,Vx (66),(ev) -+8b: vpcompressd/q Wx,Vx (66),(ev) -+8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) -+8d: vpermb/w Vx,Hx,Wx (66),(ev) -+8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) -+# 0x0f 0x38 0x90-0xbf (FMA) -+90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) -+91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) -+92: vgatherdps/d Vx,Hx,Wx (66),(v) -+93: vgatherqps/d Vx,Hx,Wx (66),(v) -+94: -+95: -+96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) -+97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) -+98: vfmadd132ps/d Vx,Hx,Wx (66),(v) -+99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) -+9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) -+9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) -+9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) -+9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) -+9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) -+9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) -+a0: vpscatterdd/q Wx,Vx (66),(ev) -+a1: vpscatterqd/q Wx,Vx (66),(ev) -+a2: vscatterdps/d Wx,Vx (66),(ev) -+a3: vscatterqps/d Wx,Vx (66),(ev) -+a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) -+a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) -+a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) -+a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) -+aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) -+ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) -+ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) -+ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) -+ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) -+af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) -+b4: vpmadd52luq Vx,Hx,Wx (66),(ev) -+b5: vpmadd52huq Vx,Hx,Wx (66),(ev) -+b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) -+b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) -+b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) -+b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) -+ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) -+bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) -+bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) -+bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) -+be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) -+bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) -+# 0x0f 0x38 0xc0-0xff -+c4: vpconflictd/q Vx,Wx (66),(ev) -+c6: Grp18 (1A) -+c7: Grp19 (1A) -+c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) -+c9: sha1msg1 Vdq,Wdq -+ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) -+cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) -+cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) -+cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) -+db: VAESIMC Vdq,Wdq (66),(v1) -+dc: VAESENC Vdq,Hdq,Wdq (66),(v1) -+dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) -+de: VAESDEC Vdq,Hdq,Wdq (66),(v1) -+df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) -+f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) -+f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) -+f2: ANDN Gy,By,Ey (v) -+f3: Grp17 (1A) -+f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) -+f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) -+f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) -+EndTable -+ -+Table: 3-byte opcode 2 (0x0f 0x3a) -+Referrer: 3-byte escape 2 -+AVXcode: 3 -+# 0x0f 0x3a 0x00-0xff -+00: vpermq Vqq,Wqq,Ib (66),(v) -+01: vpermpd Vqq,Wqq,Ib (66),(v) -+02: vpblendd Vx,Hx,Wx,Ib (66),(v) -+03: valignd/q Vx,Hx,Wx,Ib (66),(ev) -+04: vpermilps Vx,Wx,Ib (66),(v) -+05: vpermilpd Vx,Wx,Ib (66),(v) -+06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) -+07: -+08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) -+09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) -+0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) -+0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) -+0c: vblendps Vx,Hx,Wx,Ib (66) -+0d: vblendpd Vx,Hx,Wx,Ib (66) -+0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) -+0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) -+14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) -+15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) -+16: vpextrd/q Ey,Vdq,Ib (66),(v1) -+17: vextractps Ed,Vdq,Ib (66),(v1) -+18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) -+19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) -+1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) -+1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) -+1d: vcvtps2ph Wx,Vx,Ib (66),(v) -+1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) -+1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) -+20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) -+21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) -+22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) -+23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) -+25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) -+26: vgetmantps/d Vx,Wx,Ib (66),(ev) -+27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) -+30: kshiftrb/w Vk,Uk,Ib (66),(v) -+31: kshiftrd/q Vk,Uk,Ib (66),(v) -+32: kshiftlb/w Vk,Uk,Ib (66),(v) -+33: kshiftld/q Vk,Uk,Ib (66),(v) -+38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) -+39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) -+3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) -+3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) -+3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) -+3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) -+40: vdpps Vx,Hx,Wx,Ib (66) -+41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) -+42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) -+43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) -+44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) -+46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) -+4a: vblendvps Vx,Hx,Wx,Lx (66),(v) -+4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) -+4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) -+50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) -+51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) -+54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) -+55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) -+56: vreduceps/d Vx,Wx,Ib (66),(ev) -+57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) -+60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) -+61: vpcmpestri Vdq,Wdq,Ib (66),(v1) -+62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) -+63: vpcmpistri Vdq,Wdq,Ib (66),(v1) -+66: vfpclassps/d Vk,Wx,Ib (66),(ev) -+67: vfpclassss/d Vk,Wx,Ib (66),(ev) -+cc: sha1rnds4 Vdq,Wdq,Ib -+df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) -+f0: RORX Gy,Ey,Ib (F2),(v) -+EndTable -+ -+GrpTable: Grp1 -+0: ADD -+1: OR -+2: ADC -+3: SBB -+4: AND -+5: SUB -+6: XOR -+7: CMP -+EndTable -+ -+GrpTable: Grp1A -+0: POP -+EndTable -+ -+GrpTable: Grp2 -+0: ROL -+1: ROR -+2: RCL -+3: RCR -+4: SHL/SAL -+5: SHR -+6: -+7: SAR -+EndTable -+ -+GrpTable: Grp3_1 -+0: TEST Eb,Ib -+1: -+2: NOT Eb -+3: NEG Eb -+4: MUL AL,Eb -+5: IMUL AL,Eb -+6: DIV AL,Eb -+7: IDIV AL,Eb -+EndTable -+ -+GrpTable: Grp3_2 -+0: TEST Ev,Iz -+1: -+2: NOT Ev -+3: NEG Ev -+4: MUL rAX,Ev -+5: IMUL rAX,Ev -+6: DIV rAX,Ev -+7: IDIV rAX,Ev -+EndTable -+ -+GrpTable: Grp4 -+0: INC Eb -+1: DEC Eb -+EndTable -+ -+GrpTable: Grp5 -+0: INC Ev -+1: DEC Ev -+# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). -+2: CALLN Ev (f64) -+3: CALLF Ep -+4: JMPN Ev (f64) -+5: JMPF Mp -+6: PUSH Ev (d64) -+7: -+EndTable -+ -+GrpTable: Grp6 -+0: SLDT Rv/Mw -+1: STR Rv/Mw -+2: LLDT Ew -+3: LTR Ew -+4: VERR Ew -+5: VERW Ew -+EndTable -+ -+GrpTable: Grp7 -+0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) -+1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) -+2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) -+3: LIDT Ms -+4: SMSW Mw/Rv -+5: rdpkru (110),(11B) | wrpkru (111),(11B) -+6: LMSW Ew -+7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) -+EndTable -+ -+GrpTable: Grp8 -+4: BT -+5: BTS -+6: BTR -+7: BTC -+EndTable -+ -+GrpTable: Grp9 -+1: CMPXCHG8B/16B Mq/Mdq -+3: xrstors -+4: xsavec -+5: xsaves -+6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) -+7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) -+EndTable -+ -+GrpTable: Grp10 -+# all are UD1 -+0: UD1 -+1: UD1 -+2: UD1 -+3: UD1 -+4: UD1 -+5: UD1 -+6: UD1 -+7: UD1 -+EndTable -+ -+# Grp11A and Grp11B are expressed as Grp11 in Intel SDM -+GrpTable: Grp11A -+0: MOV Eb,Ib -+7: XABORT Ib (000),(11B) -+EndTable -+ -+GrpTable: Grp11B -+0: MOV Eb,Iz -+7: XBEGIN Jz (000),(11B) -+EndTable -+ -+GrpTable: Grp12 -+2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) -+4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) -+6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) -+EndTable -+ -+GrpTable: Grp13 -+0: vprord/q Hx,Wx,Ib (66),(ev) -+1: vprold/q Hx,Wx,Ib (66),(ev) -+2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) -+4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) -+6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) -+EndTable -+ -+GrpTable: Grp14 -+2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) -+3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) -+6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) -+7: vpslldq Hx,Ux,Ib (66),(11B),(v1) -+EndTable -+ -+GrpTable: Grp15 -+0: fxsave | RDFSBASE Ry (F3),(11B) -+1: fxstor | RDGSBASE Ry (F3),(11B) -+2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) -+3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) -+4: XSAVE | ptwrite Ey (F3),(11B) -+5: XRSTOR | lfence (11B) -+6: XSAVEOPT | clwb (66) | mfence (11B) -+7: clflush | clflushopt (66) | sfence (11B) -+EndTable -+ -+GrpTable: Grp16 -+0: prefetch NTA -+1: prefetch T0 -+2: prefetch T1 -+3: prefetch T2 -+EndTable -+ -+GrpTable: Grp17 -+1: BLSR By,Ey (v) -+2: BLSMSK By,Ey (v) -+3: BLSI By,Ey (v) -+EndTable -+ -+GrpTable: Grp18 -+1: vgatherpf0dps/d Wx (66),(ev) -+2: vgatherpf1dps/d Wx (66),(ev) -+5: vscatterpf0dps/d Wx (66),(ev) -+6: vscatterpf1dps/d Wx (66),(ev) -+EndTable -+ -+GrpTable: Grp19 -+1: vgatherpf0qps/d Wx (66),(ev) -+2: vgatherpf1qps/d Wx (66),(ev) -+5: vscatterpf0qps/d Wx (66),(ev) -+6: vscatterpf1qps/d Wx (66),(ev) -+EndTable -+ -+# AMD's Prefetch Group -+GrpTable: GrpP -+0: PREFETCH -+1: PREFETCHW -+EndTable -+ -+GrpTable: GrpPDLK -+0: MONTMUL -+1: XSHA1 -+2: XSHA2 -+EndTable -+ -+GrpTable: GrpRNG -+0: xstore-rng -+1: xcrypt-ecb -+2: xcrypt-cbc -+4: xcrypt-cfb -+5: xcrypt-ofb -+EndTable -diff --git a/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk -new file mode 100644 -index 0000000..b02a36b ---- /dev/null -+++ b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk -@@ -0,0 +1,393 @@ -+#!/bin/awk -f -+# SPDX-License-Identifier: GPL-2.0 -+# gen-insn-attr-x86.awk: Instruction attribute table generator -+# Written by Masami Hiramatsu <mhiramat@redhat.com> -+# -+# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c -+ -+# Awk implementation sanity check -+function check_awk_implement() { -+ if (sprintf("%x", 0) != "0") -+ return "Your awk has a printf-format problem." -+ return "" -+} -+ -+# Clear working vars -+function clear_vars() { -+ delete table -+ delete lptable2 -+ delete lptable1 -+ delete lptable3 -+ eid = -1 # escape id -+ gid = -1 # group id -+ aid = -1 # AVX id -+ tname = "" -+} -+ -+BEGIN { -+ # Implementation error checking -+ awkchecked = check_awk_implement() -+ if (awkchecked != "") { -+ print "Error: " awkchecked > "/dev/stderr" -+ print "Please try to use gawk." > "/dev/stderr" -+ exit 1 -+ } -+ -+ # Setup generating tables -+ print "/* x86 opcode map generated from x86-opcode-map.txt */" -+ print "/* Do not change this code. */\n" -+ ggid = 1 -+ geid = 1 -+ gaid = 0 -+ delete etable -+ delete gtable -+ delete atable -+ -+ opnd_expr = "^[A-Za-z/]" -+ ext_expr = "^\\(" -+ sep_expr = "^\\|$" -+ group_expr = "^Grp[0-9A-Za-z]+" -+ -+ imm_expr = "^[IJAOL][a-z]" -+ imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" -+ imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" -+ imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" -+ imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" -+ imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" -+ imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" -+ imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" -+ imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" -+ imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" -+ imm_flag["Ob"] = "INAT_MOFFSET" -+ imm_flag["Ov"] = "INAT_MOFFSET" -+ imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" -+ -+ modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" -+ force64_expr = "\\([df]64\\)" -+ rex_expr = "^REX(\\.[XRWB]+)*" -+ fpu_expr = "^ESC" # TODO -+ -+ lprefix1_expr = "\\((66|!F3)\\)" -+ lprefix2_expr = "\\(F3\\)" -+ lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)" -+ lprefix_expr = "\\((66|F2|F3)\\)" -+ max_lprefix = 4 -+ -+ # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript -+ # accepts VEX prefix -+ vexok_opcode_expr = "^[vk].*" -+ vexok_expr = "\\(v1\\)" -+ # All opcodes with (v) superscript supports *only* VEX prefix -+ vexonly_expr = "\\(v\\)" -+ # All opcodes with (ev) superscript supports *only* EVEX prefix -+ evexonly_expr = "\\(ev\\)" -+ -+ prefix_expr = "\\(Prefix\\)" -+ prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" -+ prefix_num["REPNE"] = "INAT_PFX_REPNE" -+ prefix_num["REP/REPE"] = "INAT_PFX_REPE" -+ prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" -+ prefix_num["XRELEASE"] = "INAT_PFX_REPE" -+ prefix_num["LOCK"] = "INAT_PFX_LOCK" -+ prefix_num["SEG=CS"] = "INAT_PFX_CS" -+ prefix_num["SEG=DS"] = "INAT_PFX_DS" -+ prefix_num["SEG=ES"] = "INAT_PFX_ES" -+ prefix_num["SEG=FS"] = "INAT_PFX_FS" -+ prefix_num["SEG=GS"] = "INAT_PFX_GS" -+ prefix_num["SEG=SS"] = "INAT_PFX_SS" -+ prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" -+ prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" -+ prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" -+ prefix_num["EVEX"] = "INAT_PFX_EVEX" -+ -+ clear_vars() -+} -+ -+function semantic_error(msg) { -+ print "Semantic error at " NR ": " msg > "/dev/stderr" -+ exit 1 -+} -+ -+function debug(msg) { -+ print "DEBUG: " msg -+} -+ -+function array_size(arr, i,c) { -+ c = 0 -+ for (i in arr) -+ c++ -+ return c -+} -+ -+/^Table:/ { -+ print "/* " $0 " */" -+ if (tname != "") -+ semantic_error("Hit Table: before EndTable:."); -+} -+ -+/^Referrer:/ { -+ if (NF != 1) { -+ # escape opcode table -+ ref = "" -+ for (i = 2; i <= NF; i++) -+ ref = ref $i -+ eid = escape[ref] -+ tname = sprintf("inat_escape_table_%d", eid) -+ } -+} -+ -+/^AVXcode:/ { -+ if (NF != 1) { -+ # AVX/escape opcode table -+ aid = $2 -+ if (gaid <= aid) -+ gaid = aid + 1 -+ if (tname == "") # AVX only opcode table -+ tname = sprintf("inat_avx_table_%d", $2) -+ } -+ if (aid == -1 && eid == -1) # primary opcode table -+ tname = "inat_primary_table" -+} -+ -+/^GrpTable:/ { -+ print "/* " $0 " */" -+ if (!($2 in group)) -+ semantic_error("No group: " $2 ) -+ gid = group[$2] -+ tname = "inat_group_table_" gid -+} -+ -+function print_table(tbl,name,fmt,n) -+{ -+ print "const insn_attr_t " name " = {" -+ for (i = 0; i < n; i++) { -+ id = sprintf(fmt, i) -+ if (tbl[id]) -+ print " [" id "] = " tbl[id] "," -+ } -+ print "};" -+} -+ -+/^EndTable/ { -+ if (gid != -1) { -+ # print group tables -+ if (array_size(table) != 0) { -+ print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", -+ "0x%x", 8) -+ gtable[gid,0] = tname -+ } -+ if (array_size(lptable1) != 0) { -+ print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", -+ "0x%x", 8) -+ gtable[gid,1] = tname "_1" -+ } -+ if (array_size(lptable2) != 0) { -+ print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", -+ "0x%x", 8) -+ gtable[gid,2] = tname "_2" -+ } -+ if (array_size(lptable3) != 0) { -+ print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", -+ "0x%x", 8) -+ gtable[gid,3] = tname "_3" -+ } -+ } else { -+ # print primary/escaped tables -+ if (array_size(table) != 0) { -+ print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", -+ "0x%02x", 256) -+ etable[eid,0] = tname -+ if (aid >= 0) -+ atable[aid,0] = tname -+ } -+ if (array_size(lptable1) != 0) { -+ print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", -+ "0x%02x", 256) -+ etable[eid,1] = tname "_1" -+ if (aid >= 0) -+ atable[aid,1] = tname "_1" -+ } -+ if (array_size(lptable2) != 0) { -+ print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", -+ "0x%02x", 256) -+ etable[eid,2] = tname "_2" -+ if (aid >= 0) -+ atable[aid,2] = tname "_2" -+ } -+ if (array_size(lptable3) != 0) { -+ print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", -+ "0x%02x", 256) -+ etable[eid,3] = tname "_3" -+ if (aid >= 0) -+ atable[aid,3] = tname "_3" -+ } -+ } -+ print "" -+ clear_vars() -+} -+ -+function add_flags(old,new) { -+ if (old && new) -+ return old " | " new -+ else if (old) -+ return old -+ else -+ return new -+} -+ -+# convert operands to flags. -+function convert_operands(count,opnd, i,j,imm,mod) -+{ -+ imm = null -+ mod = null -+ for (j = 1; j <= count; j++) { -+ i = opnd[j] -+ if (match(i, imm_expr) == 1) { -+ if (!imm_flag[i]) -+ semantic_error("Unknown imm opnd: " i) -+ if (imm) { -+ if (i != "Ib") -+ semantic_error("Second IMM error") -+ imm = add_flags(imm, "INAT_SCNDIMM") -+ } else -+ imm = imm_flag[i] -+ } else if (match(i, modrm_expr)) -+ mod = "INAT_MODRM" -+ } -+ return add_flags(imm, mod) -+} -+ -+/^[0-9a-f]+\:/ { -+ if (NR == 1) -+ next -+ # get index -+ idx = "0x" substr($1, 1, index($1,":") - 1) -+ if (idx in table) -+ semantic_error("Redefine " idx " in " tname) -+ -+ # check if escaped opcode -+ if ("escape" == $2) { -+ if ($3 != "#") -+ semantic_error("No escaped name") -+ ref = "" -+ for (i = 4; i <= NF; i++) -+ ref = ref $i -+ if (ref in escape) -+ semantic_error("Redefine escape (" ref ")") -+ escape[ref] = geid -+ geid++ -+ table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" -+ next -+ } -+ -+ variant = null -+ # converts -+ i = 2 -+ while (i <= NF) { -+ opcode = $(i++) -+ delete opnds -+ ext = null -+ flags = null -+ opnd = null -+ # parse one opcode -+ if (match($i, opnd_expr)) { -+ opnd = $i -+ count = split($(i++), opnds, ",") -+ flags = convert_operands(count, opnds) -+ } -+ if (match($i, ext_expr)) -+ ext = $(i++) -+ if (match($i, sep_expr)) -+ i++ -+ else if (i < NF) -+ semantic_error($i " is not a separator") -+ -+ # check if group opcode -+ if (match(opcode, group_expr)) { -+ if (!(opcode in group)) { -+ group[opcode] = ggid -+ ggid++ -+ } -+ flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") -+ } -+ # check force(or default) 64bit -+ if (match(ext, force64_expr)) -+ flags = add_flags(flags, "INAT_FORCE64") -+ -+ # check REX prefix -+ if (match(opcode, rex_expr)) -+ flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") -+ -+ # check coprocessor escape : TODO -+ if (match(opcode, fpu_expr)) -+ flags = add_flags(flags, "INAT_MODRM") -+ -+ # check VEX codes -+ if (match(ext, evexonly_expr)) -+ flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") -+ else if (match(ext, vexonly_expr)) -+ flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") -+ else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) -+ flags = add_flags(flags, "INAT_VEXOK") -+ -+ # check prefixes -+ if (match(ext, prefix_expr)) { -+ if (!prefix_num[opcode]) -+ semantic_error("Unknown prefix: " opcode) -+ flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") -+ } -+ if (length(flags) == 0) -+ continue -+ # check if last prefix -+ if (match(ext, lprefix1_expr)) { -+ lptable1[idx] = add_flags(lptable1[idx],flags) -+ variant = "INAT_VARIANT" -+ } -+ if (match(ext, lprefix2_expr)) { -+ lptable2[idx] = add_flags(lptable2[idx],flags) -+ variant = "INAT_VARIANT" -+ } -+ if (match(ext, lprefix3_expr)) { -+ lptable3[idx] = add_flags(lptable3[idx],flags) -+ variant = "INAT_VARIANT" -+ } -+ if (!match(ext, lprefix_expr)){ -+ table[idx] = add_flags(table[idx],flags) -+ } -+ } -+ if (variant) -+ table[idx] = add_flags(table[idx],variant) -+} -+ -+END { -+ if (awkchecked != "") -+ exit 1 -+ # print escape opcode map's array -+ print "/* Escape opcode map array */" -+ print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ -+ "[INAT_LSTPFX_MAX + 1] = {" -+ for (i = 0; i < geid; i++) -+ for (j = 0; j < max_lprefix; j++) -+ if (etable[i,j]) -+ print " ["i"]["j"] = "etable[i,j]"," -+ print "};\n" -+ # print group opcode map's array -+ print "/* Group opcode map array */" -+ print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ -+ "[INAT_LSTPFX_MAX + 1] = {" -+ for (i = 0; i < ggid; i++) -+ for (j = 0; j < max_lprefix; j++) -+ if (gtable[i,j]) -+ print " ["i"]["j"] = "gtable[i,j]"," -+ print "};\n" -+ # print AVX opcode map's array -+ print "/* AVX opcode map array */" -+ print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ -+ "[INAT_LSTPFX_MAX + 1] = {" -+ for (i = 0; i < gaid; i++) -+ for (j = 0; j < max_lprefix; j++) -+ if (atable[i,j]) -+ print " ["i"]["j"] = "atable[i,j]"," -+ print "};" -+} -+ -diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c -index 365c34e..694abc6 100644 ---- a/tools/objtool/builtin-check.c -+++ b/tools/objtool/builtin-check.c -@@ -29,7 +29,7 @@ - #include "builtin.h" - #include "check.h" - --bool nofp; -+bool no_fp, no_unreachable, retpoline, module; - - static const char * const check_usage[] = { - "objtool check [<options>] file.o", -@@ -37,7 +37,10 @@ static const char * const check_usage[] = { - }; - - const struct option check_options[] = { -- OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"), -+ OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), -+ OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), -+ OPT_BOOLEAN('r', "retpoline", &retpoline, "Validate retpoline assumptions"), -+ OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"), - OPT_END(), - }; - -@@ -52,5 +55,5 @@ int cmd_check(int argc, const char **argv) - - objname = argv[0]; - -- return check(objname, nofp); -+ return check(objname, false); - } -diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c -new file mode 100644 -index 0000000..77ea2b9 ---- /dev/null -+++ b/tools/objtool/builtin-orc.c -@@ -0,0 +1,68 @@ -+/* -+ * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+/* -+ * objtool orc: -+ * -+ * This command analyzes a .o file and adds .orc_unwind and .orc_unwind_ip -+ * sections to it, which is used by the in-kernel ORC unwinder. -+ * -+ * This command is a superset of "objtool check". -+ */ -+ -+#include <string.h> -+#include "builtin.h" -+#include "check.h" -+ -+ -+static const char *orc_usage[] = { -+ "objtool orc generate [<options>] file.o", -+ "objtool orc dump file.o", -+ NULL, -+}; -+ -+int cmd_orc(int argc, const char **argv) -+{ -+ const char *objname; -+ -+ argc--; argv++; -+ if (argc <= 0) -+ usage_with_options(orc_usage, check_options); -+ -+ if (!strncmp(argv[0], "gen", 3)) { -+ argc = parse_options(argc, argv, check_options, orc_usage, 0); -+ if (argc != 1) -+ usage_with_options(orc_usage, check_options); -+ -+ objname = argv[0]; -+ -+ return check(objname, true); -+ } -+ -+ if (!strcmp(argv[0], "dump")) { -+ if (argc != 2) -+ usage_with_options(orc_usage, check_options); -+ -+ objname = argv[1]; -+ -+ return orc_dump(objname); -+ } -+ -+ usage_with_options(orc_usage, check_options); -+ -+ return 0; -+} -diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h -index 34d2ba7..28ff40e 100644 ---- a/tools/objtool/builtin.h -+++ b/tools/objtool/builtin.h -@@ -17,6 +17,12 @@ - #ifndef _BUILTIN_H - #define _BUILTIN_H - -+#include <subcmd/parse-options.h> -+ -+extern const struct option check_options[]; -+extern bool no_fp, no_unreachable, retpoline, module; -+ - extern int cmd_check(int argc, const char **argv); -+extern int cmd_orc(int argc, const char **argv); - - #endif /* _BUILTIN_H */ -diff --git a/tools/objtool/cfi.h b/tools/objtool/cfi.h -new file mode 100644 -index 0000000..2fe883c ---- /dev/null -+++ b/tools/objtool/cfi.h -@@ -0,0 +1,55 @@ -+/* -+ * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#ifndef _OBJTOOL_CFI_H -+#define _OBJTOOL_CFI_H -+ -+#define CFI_UNDEFINED -1 -+#define CFI_CFA -2 -+#define CFI_SP_INDIRECT -3 -+#define CFI_BP_INDIRECT -4 -+ -+#define CFI_AX 0 -+#define CFI_DX 1 -+#define CFI_CX 2 -+#define CFI_BX 3 -+#define CFI_SI 4 -+#define CFI_DI 5 -+#define CFI_BP 6 -+#define CFI_SP 7 -+#define CFI_R8 8 -+#define CFI_R9 9 -+#define CFI_R10 10 -+#define CFI_R11 11 -+#define CFI_R12 12 -+#define CFI_R13 13 -+#define CFI_R14 14 -+#define CFI_R15 15 -+#define CFI_RA 16 -+#define CFI_NUM_REGS 17 -+ -+struct cfi_reg { -+ int base; -+ int offset; -+}; -+ -+struct cfi_state { -+ struct cfi_reg cfa; -+ struct cfi_reg regs[CFI_NUM_REGS]; -+}; -+ -+#endif /* _OBJTOOL_CFI_H */ -diff --git a/tools/objtool/check.c b/tools/objtool/check.c -index b7a0af5..c8b8b71 100644 ---- a/tools/objtool/check.c -+++ b/tools/objtool/check.c -@@ -18,6 +18,7 @@ - #include <string.h> - #include <stdlib.h> - -+#include "builtin.h" - #include "check.h" - #include "elf.h" - #include "special.h" -@@ -25,12 +26,7 @@ - #include "warn.h" - - #include <linux/hashtable.h> -- --#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -- --#define STATE_FP_SAVED 0x1 --#define STATE_FP_SETUP 0x2 --#define STATE_FENTRY 0x4 -+#include <linux/kernel.h> - - struct alternative { - struct list_head list; -@@ -38,10 +34,10 @@ struct alternative { - }; - - const char *objname; --static bool nofp; -+struct cfi_state initial_func_cfi; - --static struct instruction *find_insn(struct objtool_file *file, -- struct section *sec, unsigned long offset) -+struct instruction *find_insn(struct objtool_file *file, -+ struct section *sec, unsigned long offset) - { - struct instruction *insn; - -@@ -57,28 +53,12 @@ static struct instruction *next_insn_same_sec(struct objtool_file *file, - { - struct instruction *next = list_next_entry(insn, list); - -- if (&next->list == &file->insn_list || next->sec != insn->sec) -+ if (!next || &next->list == &file->insn_list || next->sec != insn->sec) - return NULL; - - return next; - } - --static bool gcov_enabled(struct objtool_file *file) --{ -- struct section *sec; -- struct symbol *sym; -- -- list_for_each_entry(sec, &file->elf->sections, list) -- list_for_each_entry(sym, &sec->symbol_list, list) -- if (!strncmp(sym->name, "__gcov_.", 8)) -- return true; -- -- return false; --} -- --#define for_each_insn(file, insn) \ -- list_for_each_entry(insn, &file->insn_list, list) -- - #define func_for_each_insn(file, func, insn) \ - for (insn = find_insn(file, func->sec, func->offset); \ - insn && &insn->list != &file->insn_list && \ -@@ -95,6 +75,9 @@ static bool gcov_enabled(struct objtool_file *file) - #define sec_for_each_insn_from(file, insn) \ - for (; insn; insn = next_insn_same_sec(file, insn)) - -+#define sec_for_each_insn_continue(file, insn) \ -+ for (insn = next_insn_same_sec(file, insn); insn; \ -+ insn = next_insn_same_sec(file, insn)) - - /* - * Check if the function has been manually whitelisted with the -@@ -104,7 +87,6 @@ static bool gcov_enabled(struct objtool_file *file) - static bool ignore_func(struct objtool_file *file, struct symbol *func) - { - struct rela *rela; -- struct instruction *insn; - - /* check for STACK_FRAME_NON_STANDARD */ - if (file->whitelist && file->whitelist->rela) -@@ -117,11 +99,6 @@ static bool ignore_func(struct objtool_file *file, struct symbol *func) - return true; - } - -- /* check if it has a context switching instruction */ -- func_for_each_insn(file, func, insn) -- if (insn->type == INSN_CONTEXT_SWITCH) -- return true; -- - return false; - } - -@@ -159,7 +136,8 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func, - "complete_and_exit", - "kvm_spurious_fault", - "__reiserfs_panic", -- "lbug_with_loc" -+ "lbug_with_loc", -+ "fortify_panic", - }; - - if (func->bind == STB_WEAK) -@@ -234,6 +212,20 @@ static int dead_end_function(struct objtool_file *file, struct symbol *func) - return __dead_end_function(file, func, 0); - } - -+static void clear_insn_state(struct insn_state *state) -+{ -+ int i; -+ -+ memset(state, 0, sizeof(*state)); -+ state->cfa.base = CFI_UNDEFINED; -+ for (i = 0; i < CFI_NUM_REGS; i++) { -+ state->regs[i].base = CFI_UNDEFINED; -+ state->vals[i].base = CFI_UNDEFINED; -+ } -+ state->drap_reg = CFI_UNDEFINED; -+ state->drap_offset = -1; -+} -+ - /* - * Call the arch-specific instruction decoder for all the instructions and add - * them to the global instruction list. -@@ -246,30 +238,42 @@ static int decode_instructions(struct objtool_file *file) - struct instruction *insn; - int ret; - -- list_for_each_entry(sec, &file->elf->sections, list) { -+ for_each_sec(file, sec) { - - if (!(sec->sh.sh_flags & SHF_EXECINSTR)) - continue; - -+ if (strcmp(sec->name, ".altinstr_replacement") && -+ strcmp(sec->name, ".altinstr_aux") && -+ strncmp(sec->name, ".discard.", 9)) -+ sec->text = true; -+ - for (offset = 0; offset < sec->len; offset += insn->len) { - insn = malloc(sizeof(*insn)); -+ if (!insn) { -+ WARN("malloc failed"); -+ return -1; -+ } - memset(insn, 0, sizeof(*insn)); -- - INIT_LIST_HEAD(&insn->alts); -+ clear_insn_state(&insn->state); -+ - insn->sec = sec; - insn->offset = offset; - - ret = arch_decode_instruction(file->elf, sec, offset, - sec->len - offset, - &insn->len, &insn->type, -- &insn->immediate); -+ &insn->immediate, -+ &insn->stack_op); - if (ret) -- return ret; -+ goto err; - - if (!insn->type || insn->type > INSN_LAST) { - WARN_FUNC("invalid instruction type %d", - insn->sec, insn->offset, insn->type); -- return -1; -+ ret = -1; -+ goto err; - } - - hash_add(file->insn_hash, &insn->hash, insn->offset); -@@ -293,10 +297,14 @@ static int decode_instructions(struct objtool_file *file) - } - - return 0; -+ -+err: -+ free(insn); -+ return ret; - } - - /* -- * Find all uses of the unreachable() macro, which are code path dead ends. -+ * Mark "ud2" instructions and manually annotated dead ends. - */ - static int add_dead_ends(struct objtool_file *file) - { -@@ -305,13 +313,24 @@ static int add_dead_ends(struct objtool_file *file) - struct instruction *insn; - bool found; - -- sec = find_section_by_name(file->elf, ".rela__unreachable"); -+ /* -+ * By default, "ud2" is a dead end unless otherwise annotated, because -+ * GCC 7 inserts it for certain divide-by-zero cases. -+ */ -+ for_each_insn(file, insn) -+ if (insn->type == INSN_BUG) -+ insn->dead_end = true; -+ -+ /* -+ * Check for manually annotated dead ends. -+ */ -+ sec = find_section_by_name(file->elf, ".rela.discard.unreachable"); - if (!sec) -- return 0; -+ goto reachable; - - list_for_each_entry(rela, &sec->rela_list, list) { - if (rela->sym->type != STT_SECTION) { -- WARN("unexpected relocation symbol type in .rela__unreachable"); -+ WARN("unexpected relocation symbol type in %s", sec->name); - return -1; - } - insn = find_insn(file, rela->sym->sec, rela->addend); -@@ -340,6 +359,48 @@ static int add_dead_ends(struct objtool_file *file) - insn->dead_end = true; - } - -+reachable: -+ /* -+ * These manually annotated reachable checks are needed for GCC 4.4, -+ * where the Linux unreachable() macro isn't supported. In that case -+ * GCC doesn't know the "ud2" is fatal, so it generates code as if it's -+ * not a dead end. -+ */ -+ sec = find_section_by_name(file->elf, ".rela.discard.reachable"); -+ if (!sec) -+ return 0; -+ -+ list_for_each_entry(rela, &sec->rela_list, list) { -+ if (rela->sym->type != STT_SECTION) { -+ WARN("unexpected relocation symbol type in %s", sec->name); -+ return -1; -+ } -+ insn = find_insn(file, rela->sym->sec, rela->addend); -+ if (insn) -+ insn = list_prev_entry(insn, list); -+ else if (rela->addend == rela->sym->sec->len) { -+ found = false; -+ list_for_each_entry_reverse(insn, &file->insn_list, list) { -+ if (insn->sec == rela->sym->sec) { -+ found = true; -+ break; -+ } -+ } -+ -+ if (!found) { -+ WARN("can't find reachable insn at %s+0x%x", -+ rela->sym->sec->name, rela->addend); -+ return -1; -+ } -+ } else { -+ WARN("can't find reachable insn at %s+0x%x", -+ rela->sym->sec->name, rela->addend); -+ return -1; -+ } -+ -+ insn->dead_end = false; -+ } -+ - return 0; - } - -@@ -352,7 +413,7 @@ static void add_ignores(struct objtool_file *file) - struct section *sec; - struct symbol *func; - -- list_for_each_entry(sec, &file->elf->sections, list) { -+ for_each_sec(file, sec) { - list_for_each_entry(func, &sec->symbol_list, list) { - if (func->type != STT_FUNC) - continue; -@@ -361,7 +422,7 @@ static void add_ignores(struct objtool_file *file) - continue; - - func_for_each_insn(file, func, insn) -- insn->visited = true; -+ insn->ignore = true; - } - } - } -@@ -415,8 +476,7 @@ static int add_jump_destinations(struct objtool_file *file) - insn->type != INSN_JUMP_UNCONDITIONAL) - continue; - -- /* skip ignores */ -- if (insn->visited) -+ if (insn->ignore) - continue; - - rela = find_rela_by_dest_range(insn->sec, insn->offset, -@@ -436,6 +496,7 @@ static int add_jump_destinations(struct objtool_file *file) - * disguise, so convert them accordingly. - */ - insn->type = INSN_JUMP_DYNAMIC; -+ insn->retpoline_safe = true; - continue; - } else { - /* sibling call */ -@@ -483,18 +544,15 @@ static int add_call_destinations(struct objtool_file *file) - dest_off = insn->offset + insn->len + insn->immediate; - insn->call_dest = find_symbol_by_offset(insn->sec, - dest_off); -- /* -- * FIXME: Thanks to retpolines, it's now considered -- * normal for a function to call within itself. So -- * disable this warning for now. -- */ --#if 0 -- if (!insn->call_dest) { -- WARN_FUNC("can't find call dest symbol at offset 0x%lx", -- insn->sec, insn->offset, dest_off); -+ -+ if (!insn->call_dest && !insn->ignore) { -+ WARN_FUNC("unsupported intra-function call", -+ insn->sec, insn->offset); -+ if (retpoline) -+ WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); - return -1; - } --#endif -+ - } else if (rela->sym->type == STT_SECTION) { - insn->call_dest = find_symbol_by_offset(rela->sym->sec, - rela->addend+4); -@@ -538,7 +596,7 @@ static int handle_group_alt(struct objtool_file *file, - struct instruction *orig_insn, - struct instruction **new_insn) - { -- struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; -+ struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL; - unsigned long dest_off; - - last_orig_insn = NULL; -@@ -554,25 +612,30 @@ static int handle_group_alt(struct objtool_file *file, - last_orig_insn = insn; - } - -- if (!next_insn_same_sec(file, last_orig_insn)) { -- WARN("%s: don't know how to handle alternatives at end of section", -- special_alt->orig_sec->name); -- return -1; -- } -- -- fake_jump = malloc(sizeof(*fake_jump)); -- if (!fake_jump) { -- WARN("malloc failed"); -- return -1; -+ if (next_insn_same_sec(file, last_orig_insn)) { -+ fake_jump = malloc(sizeof(*fake_jump)); -+ if (!fake_jump) { -+ WARN("malloc failed"); -+ return -1; -+ } -+ memset(fake_jump, 0, sizeof(*fake_jump)); -+ INIT_LIST_HEAD(&fake_jump->alts); -+ clear_insn_state(&fake_jump->state); -+ -+ fake_jump->sec = special_alt->new_sec; -+ fake_jump->offset = -1; -+ fake_jump->type = INSN_JUMP_UNCONDITIONAL; -+ fake_jump->jump_dest = list_next_entry(last_orig_insn, list); -+ fake_jump->ignore = true; - } -- memset(fake_jump, 0, sizeof(*fake_jump)); -- INIT_LIST_HEAD(&fake_jump->alts); -- fake_jump->sec = special_alt->new_sec; -- fake_jump->offset = -1; -- fake_jump->type = INSN_JUMP_UNCONDITIONAL; -- fake_jump->jump_dest = list_next_entry(last_orig_insn, list); - - if (!special_alt->new_len) { -+ if (!fake_jump) { -+ WARN("%s: empty alternative at end of section", -+ special_alt->orig_sec->name); -+ return -1; -+ } -+ - *new_insn = fake_jump; - return 0; - } -@@ -585,6 +648,8 @@ static int handle_group_alt(struct objtool_file *file, - - last_new_insn = insn; - -+ insn->ignore = orig_insn->ignore_alts; -+ - if (insn->type != INSN_JUMP_CONDITIONAL && - insn->type != INSN_JUMP_UNCONDITIONAL) - continue; -@@ -593,8 +658,14 @@ static int handle_group_alt(struct objtool_file *file, - continue; - - dest_off = insn->offset + insn->len + insn->immediate; -- if (dest_off == special_alt->new_off + special_alt->new_len) -+ if (dest_off == special_alt->new_off + special_alt->new_len) { -+ if (!fake_jump) { -+ WARN("%s: alternative jump to end of section", -+ special_alt->orig_sec->name); -+ return -1; -+ } - insn->jump_dest = fake_jump; -+ } - - if (!insn->jump_dest) { - WARN_FUNC("can't find alternative jump destination", -@@ -609,7 +680,8 @@ static int handle_group_alt(struct objtool_file *file, - return -1; - } - -- list_add(&fake_jump->list, &last_new_insn->list); -+ if (fake_jump) -+ list_add(&fake_jump->list, &last_new_insn->list); - - return 0; - } -@@ -656,6 +728,7 @@ static int add_special_section_alts(struct objtool_file *file) - return ret; - - list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { -+ - orig_insn = find_insn(file, special_alt->orig_sec, - special_alt->orig_off); - if (!orig_insn) { -@@ -665,10 +738,6 @@ static int add_special_section_alts(struct objtool_file *file) - goto out; - } - -- /* Ignore retpoline alternatives. */ -- if (orig_insn->ignore_alts) -- continue; -- - new_insn = NULL; - if (!special_alt->group || special_alt->new_len) { - new_insn = find_insn(file, special_alt->new_sec, -@@ -784,8 +853,14 @@ static int add_switch_table(struct objtool_file *file, struct symbol *func, - * This is a fairly uncommon pattern which is new for GCC 6. As of this - * writing, there are 11 occurrences of it in the allmodconfig kernel. - * -+ * As of GCC 7 there are quite a few more of these and the 'in between' code -+ * is significant. Esp. with KASAN enabled some of the code between the mov -+ * and jmpq uses .rodata itself, which can confuse things. -+ * - * TODO: Once we have DWARF CFI and smarter instruction decoding logic, - * ensure the same register is used in the mov and jump instructions. -+ * -+ * NOTE: RETPOLINE made it harder still to decode dynamic jumps. - */ - static struct rela *find_switch_table(struct objtool_file *file, - struct symbol *func, -@@ -807,12 +882,25 @@ static struct rela *find_switch_table(struct objtool_file *file, - text_rela->addend + 4); - if (!rodata_rela) - return NULL; -+ - file->ignore_unreachables = true; - return rodata_rela; - } - - /* case 3 */ -- func_for_each_insn_continue_reverse(file, func, insn) { -+ /* -+ * Backward search using the @first_jump_src links, these help avoid -+ * much of the 'in between' code. Which avoids us getting confused by -+ * it. -+ */ -+ for (insn = list_prev_entry(insn, list); -+ -+ &insn->list != &file->insn_list && -+ insn->sec == func->sec && -+ insn->offset >= func->offset; -+ -+ insn = insn->first_jump_src ?: list_prev_entry(insn, list)) { -+ - if (insn->type == INSN_JUMP_DYNAMIC) - break; - -@@ -836,20 +924,42 @@ static struct rela *find_switch_table(struct objtool_file *file, - if (find_symbol_containing(file->rodata, text_rela->addend)) - continue; - -- return find_rela_by_dest(file->rodata, text_rela->addend); -+ rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend); -+ if (!rodata_rela) -+ continue; -+ -+ return rodata_rela; - } - - return NULL; - } - -+ - static int add_func_switch_tables(struct objtool_file *file, - struct symbol *func) - { -- struct instruction *insn, *prev_jump = NULL; -+ struct instruction *insn, *last = NULL, *prev_jump = NULL; - struct rela *rela, *prev_rela = NULL; - int ret; - - func_for_each_insn(file, func, insn) { -+ if (!last) -+ last = insn; -+ -+ /* -+ * Store back-pointers for unconditional forward jumps such -+ * that find_switch_table() can back-track using those and -+ * avoid some potentially confusing code. -+ */ -+ if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest && -+ insn->offset > last->offset && -+ insn->jump_dest->offset > insn->offset && -+ !insn->jump_dest->first_jump_src) { -+ -+ insn->jump_dest->first_jump_src = insn; -+ last = insn->jump_dest; -+ } -+ - if (insn->type != INSN_JUMP_DYNAMIC) - continue; - -@@ -896,7 +1006,7 @@ static int add_switch_table_alts(struct objtool_file *file) - if (!file->rodata || !file->rodata->rela) - return 0; - -- list_for_each_entry(sec, &file->elf->sections, list) { -+ for_each_sec(file, sec) { - list_for_each_entry(func, &sec->symbol_list, list) { - if (func->type != STT_FUNC) - continue; -@@ -910,6 +1020,134 @@ static int add_switch_table_alts(struct objtool_file *file) - return 0; - } - -+static int read_unwind_hints(struct objtool_file *file) -+{ -+ struct section *sec, *relasec; -+ struct rela *rela; -+ struct unwind_hint *hint; -+ struct instruction *insn; -+ struct cfi_reg *cfa; -+ int i; -+ -+ sec = find_section_by_name(file->elf, ".discard.unwind_hints"); -+ if (!sec) -+ return 0; -+ -+ relasec = sec->rela; -+ if (!relasec) { -+ WARN("missing .rela.discard.unwind_hints section"); -+ return -1; -+ } -+ -+ if (sec->len % sizeof(struct unwind_hint)) { -+ WARN("struct unwind_hint size mismatch"); -+ return -1; -+ } -+ -+ file->hints = true; -+ -+ for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) { -+ hint = (struct unwind_hint *)sec->data->d_buf + i; -+ -+ rela = find_rela_by_dest(sec, i * sizeof(*hint)); -+ if (!rela) { -+ WARN("can't find rela for unwind_hints[%d]", i); -+ return -1; -+ } -+ -+ insn = find_insn(file, rela->sym->sec, rela->addend); -+ if (!insn) { -+ WARN("can't find insn for unwind_hints[%d]", i); -+ return -1; -+ } -+ -+ cfa = &insn->state.cfa; -+ -+ if (hint->type == UNWIND_HINT_TYPE_SAVE) { -+ insn->save = true; -+ continue; -+ -+ } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) { -+ insn->restore = true; -+ insn->hint = true; -+ continue; -+ } -+ -+ insn->hint = true; -+ -+ switch (hint->sp_reg) { -+ case ORC_REG_UNDEFINED: -+ cfa->base = CFI_UNDEFINED; -+ break; -+ case ORC_REG_SP: -+ cfa->base = CFI_SP; -+ break; -+ case ORC_REG_BP: -+ cfa->base = CFI_BP; -+ break; -+ case ORC_REG_SP_INDIRECT: -+ cfa->base = CFI_SP_INDIRECT; -+ break; -+ case ORC_REG_R10: -+ cfa->base = CFI_R10; -+ break; -+ case ORC_REG_R13: -+ cfa->base = CFI_R13; -+ break; -+ case ORC_REG_DI: -+ cfa->base = CFI_DI; -+ break; -+ case ORC_REG_DX: -+ cfa->base = CFI_DX; -+ break; -+ default: -+ WARN_FUNC("unsupported unwind_hint sp base reg %d", -+ insn->sec, insn->offset, hint->sp_reg); -+ return -1; -+ } -+ -+ cfa->offset = hint->sp_offset; -+ insn->state.type = hint->type; -+ } -+ -+ return 0; -+} -+ -+static int read_retpoline_hints(struct objtool_file *file) -+{ -+ struct section *sec; -+ struct instruction *insn; -+ struct rela *rela; -+ -+ sec = find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); -+ if (!sec) -+ return 0; -+ -+ list_for_each_entry(rela, &sec->rela_list, list) { -+ if (rela->sym->type != STT_SECTION) { -+ WARN("unexpected relocation symbol type in %s", sec->name); -+ return -1; -+ } -+ -+ insn = find_insn(file, rela->sym->sec, rela->addend); -+ if (!insn) { -+ WARN("bad .discard.retpoline_safe entry"); -+ return -1; -+ } -+ -+ if (insn->type != INSN_JUMP_DYNAMIC && -+ insn->type != INSN_CALL_DYNAMIC) { -+ WARN_FUNC("retpoline_safe hint not an indirect jump/call", -+ insn->sec, insn->offset); -+ return -1; -+ } -+ -+ insn->retpoline_safe = true; -+ } -+ -+ return 0; -+} -+ - static int decode_sections(struct objtool_file *file) - { - int ret; -@@ -932,11 +1170,11 @@ static int decode_sections(struct objtool_file *file) - if (ret) - return ret; - -- ret = add_call_destinations(file); -+ ret = add_special_section_alts(file); - if (ret) - return ret; - -- ret = add_special_section_alts(file); -+ ret = add_call_destinations(file); - if (ret) - return ret; - -@@ -944,6 +1182,14 @@ static int decode_sections(struct objtool_file *file) - if (ret) - return ret; - -+ ret = read_unwind_hints(file); -+ if (ret) -+ return ret; -+ -+ ret = read_retpoline_hints(file); -+ if (ret) -+ return ret; -+ - return 0; - } - -@@ -957,125 +1203,647 @@ static bool is_fentry_call(struct instruction *insn) - return false; - } - --static bool has_modified_stack_frame(struct instruction *insn) -+static bool has_modified_stack_frame(struct insn_state *state) -+{ -+ int i; -+ -+ if (state->cfa.base != initial_func_cfi.cfa.base || -+ state->cfa.offset != initial_func_cfi.cfa.offset || -+ state->stack_size != initial_func_cfi.cfa.offset || -+ state->drap) -+ return true; -+ -+ for (i = 0; i < CFI_NUM_REGS; i++) -+ if (state->regs[i].base != initial_func_cfi.regs[i].base || -+ state->regs[i].offset != initial_func_cfi.regs[i].offset) -+ return true; -+ -+ return false; -+} -+ -+static bool has_valid_stack_frame(struct insn_state *state) -+{ -+ if (state->cfa.base == CFI_BP && state->regs[CFI_BP].base == CFI_CFA && -+ state->regs[CFI_BP].offset == -16) -+ return true; -+ -+ if (state->drap && state->regs[CFI_BP].base == CFI_BP) -+ return true; -+ -+ return false; -+} -+ -+static int update_insn_state_regs(struct instruction *insn, struct insn_state *state) - { -- return (insn->state & STATE_FP_SAVED) || -- (insn->state & STATE_FP_SETUP); -+ struct cfi_reg *cfa = &state->cfa; -+ struct stack_op *op = &insn->stack_op; -+ -+ if (cfa->base != CFI_SP) -+ return 0; -+ -+ /* push */ -+ if (op->dest.type == OP_DEST_PUSH) -+ cfa->offset += 8; -+ -+ /* pop */ -+ if (op->src.type == OP_SRC_POP) -+ cfa->offset -= 8; -+ -+ /* add immediate to sp */ -+ if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD && -+ op->dest.reg == CFI_SP && op->src.reg == CFI_SP) -+ cfa->offset -= op->src.offset; -+ -+ return 0; - } - --static bool has_valid_stack_frame(struct instruction *insn) -+static void save_reg(struct insn_state *state, unsigned char reg, int base, -+ int offset) - { -- return (insn->state & STATE_FP_SAVED) && -- (insn->state & STATE_FP_SETUP); -+ if (arch_callee_saved_reg(reg) && -+ state->regs[reg].base == CFI_UNDEFINED) { -+ state->regs[reg].base = base; -+ state->regs[reg].offset = offset; -+ } - } - --static unsigned int frame_state(unsigned long state) -+static void restore_reg(struct insn_state *state, unsigned char reg) - { -- return (state & (STATE_FP_SAVED | STATE_FP_SETUP)); -+ state->regs[reg].base = CFI_UNDEFINED; -+ state->regs[reg].offset = 0; - } - - /* -- * Follow the branch starting at the given instruction, and recursively follow -- * any other branches (jumps). Meanwhile, track the frame pointer state at -- * each instruction and validate all the rules described in -- * tools/objtool/Documentation/stack-validation.txt. -+ * A note about DRAP stack alignment: -+ * -+ * GCC has the concept of a DRAP register, which is used to help keep track of -+ * the stack pointer when aligning the stack. r10 or r13 is used as the DRAP -+ * register. The typical DRAP pattern is: -+ * -+ * 4c 8d 54 24 08 lea 0x8(%rsp),%r10 -+ * 48 83 e4 c0 and $0xffffffffffffffc0,%rsp -+ * 41 ff 72 f8 pushq -0x8(%r10) -+ * 55 push %rbp -+ * 48 89 e5 mov %rsp,%rbp -+ * (more pushes) -+ * 41 52 push %r10 -+ * ... -+ * 41 5a pop %r10 -+ * (more pops) -+ * 5d pop %rbp -+ * 49 8d 62 f8 lea -0x8(%r10),%rsp -+ * c3 retq -+ * -+ * There are some variations in the epilogues, like: -+ * -+ * 5b pop %rbx -+ * 41 5a pop %r10 -+ * 41 5c pop %r12 -+ * 41 5d pop %r13 -+ * 41 5e pop %r14 -+ * c9 leaveq -+ * 49 8d 62 f8 lea -0x8(%r10),%rsp -+ * c3 retq -+ * -+ * and: -+ * -+ * 4c 8b 55 e8 mov -0x18(%rbp),%r10 -+ * 48 8b 5d e0 mov -0x20(%rbp),%rbx -+ * 4c 8b 65 f0 mov -0x10(%rbp),%r12 -+ * 4c 8b 6d f8 mov -0x8(%rbp),%r13 -+ * c9 leaveq -+ * 49 8d 62 f8 lea -0x8(%r10),%rsp -+ * c3 retq -+ * -+ * Sometimes r13 is used as the DRAP register, in which case it's saved and -+ * restored beforehand: -+ * -+ * 41 55 push %r13 -+ * 4c 8d 6c 24 10 lea 0x10(%rsp),%r13 -+ * 48 83 e4 f0 and $0xfffffffffffffff0,%rsp -+ * ... -+ * 49 8d 65 f0 lea -0x10(%r13),%rsp -+ * 41 5d pop %r13 -+ * c3 retq - */ --static int validate_branch(struct objtool_file *file, -- struct instruction *first, unsigned char first_state) -+static int update_insn_state(struct instruction *insn, struct insn_state *state) - { -- struct alternative *alt; -- struct instruction *insn; -- struct section *sec; -- struct symbol *func = NULL; -- unsigned char state; -- int ret; -+ struct stack_op *op = &insn->stack_op; -+ struct cfi_reg *cfa = &state->cfa; -+ struct cfi_reg *regs = state->regs; -+ -+ /* stack operations don't make sense with an undefined CFA */ -+ if (cfa->base == CFI_UNDEFINED) { -+ if (insn->func) { -+ WARN_FUNC("undefined stack state", insn->sec, insn->offset); -+ return -1; -+ } -+ return 0; -+ } - -- insn = first; -- sec = insn->sec; -- state = first_state; -+ if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET) -+ return update_insn_state_regs(insn, state); - -- if (insn->alt_group && list_empty(&insn->alts)) { -- WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", -- sec, insn->offset); -- return 1; -- } -+ switch (op->dest.type) { - -- while (1) { -- if (file->c_file && insn->func) { -- if (func && func != insn->func) { -- WARN("%s() falls through to next function %s()", -- func->name, insn->func->name); -- return 1; -- } -+ case OP_DEST_REG: -+ switch (op->src.type) { - -- func = insn->func; -- } -+ case OP_SRC_REG: -+ if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP && -+ cfa->base == CFI_SP && -+ regs[CFI_BP].base == CFI_CFA && -+ regs[CFI_BP].offset == -cfa->offset) { - -- if (insn->visited) { -- if (frame_state(insn->state) != frame_state(state)) { -- WARN_FUNC("frame pointer state mismatch", -- sec, insn->offset); -- return 1; -+ /* mov %rsp, %rbp */ -+ cfa->base = op->dest.reg; -+ state->bp_scratch = false; - } - -- return 0; -+ else if (op->src.reg == CFI_SP && -+ op->dest.reg == CFI_BP && state->drap) { -+ -+ /* drap: mov %rsp, %rbp */ -+ regs[CFI_BP].base = CFI_BP; -+ regs[CFI_BP].offset = -state->stack_size; -+ state->bp_scratch = false; -+ } -+ -+ else if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { -+ -+ /* -+ * mov %rsp, %reg -+ * -+ * This is needed for the rare case where GCC -+ * does: -+ * -+ * mov %rsp, %rax -+ * ... -+ * mov %rax, %rsp -+ */ -+ state->vals[op->dest.reg].base = CFI_CFA; -+ state->vals[op->dest.reg].offset = -state->stack_size; -+ } -+ -+ else if (op->src.reg == CFI_BP && op->dest.reg == CFI_SP && -+ cfa->base == CFI_BP) { -+ -+ /* -+ * mov %rbp, %rsp -+ * -+ * Restore the original stack pointer (Clang). -+ */ -+ state->stack_size = -state->regs[CFI_BP].offset; -+ } -+ -+ else if (op->dest.reg == cfa->base) { -+ -+ /* mov %reg, %rsp */ -+ if (cfa->base == CFI_SP && -+ state->vals[op->src.reg].base == CFI_CFA) { -+ -+ /* -+ * This is needed for the rare case -+ * where GCC does something dumb like: -+ * -+ * lea 0x8(%rsp), %rcx -+ * ... -+ * mov %rcx, %rsp -+ */ -+ cfa->offset = -state->vals[op->src.reg].offset; -+ state->stack_size = cfa->offset; -+ -+ } else { -+ cfa->base = CFI_UNDEFINED; -+ cfa->offset = 0; -+ } -+ } -+ -+ break; -+ -+ case OP_SRC_ADD: -+ if (op->dest.reg == CFI_SP && op->src.reg == CFI_SP) { -+ -+ /* add imm, %rsp */ -+ state->stack_size -= op->src.offset; -+ if (cfa->base == CFI_SP) -+ cfa->offset -= op->src.offset; -+ break; -+ } -+ -+ if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { -+ -+ /* lea disp(%rbp), %rsp */ -+ state->stack_size = -(op->src.offset + regs[CFI_BP].offset); -+ break; -+ } -+ -+ if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { -+ -+ /* drap: lea disp(%rsp), %drap */ -+ state->drap_reg = op->dest.reg; -+ -+ /* -+ * lea disp(%rsp), %reg -+ * -+ * This is needed for the rare case where GCC -+ * does something dumb like: -+ * -+ * lea 0x8(%rsp), %rcx -+ * ... -+ * mov %rcx, %rsp -+ */ -+ state->vals[op->dest.reg].base = CFI_CFA; -+ state->vals[op->dest.reg].offset = \ -+ -state->stack_size + op->src.offset; -+ -+ break; -+ } -+ -+ if (state->drap && op->dest.reg == CFI_SP && -+ op->src.reg == state->drap_reg) { -+ -+ /* drap: lea disp(%drap), %rsp */ -+ cfa->base = CFI_SP; -+ cfa->offset = state->stack_size = -op->src.offset; -+ state->drap_reg = CFI_UNDEFINED; -+ state->drap = false; -+ break; -+ } -+ -+ if (op->dest.reg == state->cfa.base) { -+ WARN_FUNC("unsupported stack register modification", -+ insn->sec, insn->offset); -+ return -1; -+ } -+ -+ break; -+ -+ case OP_SRC_AND: -+ if (op->dest.reg != CFI_SP || -+ (state->drap_reg != CFI_UNDEFINED && cfa->base != CFI_SP) || -+ (state->drap_reg == CFI_UNDEFINED && cfa->base != CFI_BP)) { -+ WARN_FUNC("unsupported stack pointer realignment", -+ insn->sec, insn->offset); -+ return -1; -+ } -+ -+ if (state->drap_reg != CFI_UNDEFINED) { -+ /* drap: and imm, %rsp */ -+ cfa->base = state->drap_reg; -+ cfa->offset = state->stack_size = 0; -+ state->drap = true; -+ } -+ -+ /* -+ * Older versions of GCC (4.8ish) realign the stack -+ * without DRAP, with a frame pointer. -+ */ -+ -+ break; -+ -+ case OP_SRC_POP: -+ if (!state->drap && op->dest.type == OP_DEST_REG && -+ op->dest.reg == cfa->base) { -+ -+ /* pop %rbp */ -+ cfa->base = CFI_SP; -+ } -+ -+ if (state->drap && cfa->base == CFI_BP_INDIRECT && -+ op->dest.type == OP_DEST_REG && -+ op->dest.reg == state->drap_reg && -+ state->drap_offset == -state->stack_size) { -+ -+ /* drap: pop %drap */ -+ cfa->base = state->drap_reg; -+ cfa->offset = 0; -+ state->drap_offset = -1; -+ -+ } else if (regs[op->dest.reg].offset == -state->stack_size) { -+ -+ /* pop %reg */ -+ restore_reg(state, op->dest.reg); -+ } -+ -+ state->stack_size -= 8; -+ if (cfa->base == CFI_SP) -+ cfa->offset -= 8; -+ -+ break; -+ -+ case OP_SRC_REG_INDIRECT: -+ if (state->drap && op->src.reg == CFI_BP && -+ op->src.offset == state->drap_offset) { -+ -+ /* drap: mov disp(%rbp), %drap */ -+ cfa->base = state->drap_reg; -+ cfa->offset = 0; -+ state->drap_offset = -1; -+ } -+ -+ if (state->drap && op->src.reg == CFI_BP && -+ op->src.offset == regs[op->dest.reg].offset) { -+ -+ /* drap: mov disp(%rbp), %reg */ -+ restore_reg(state, op->dest.reg); -+ -+ } else if (op->src.reg == cfa->base && -+ op->src.offset == regs[op->dest.reg].offset + cfa->offset) { -+ -+ /* mov disp(%rbp), %reg */ -+ /* mov disp(%rsp), %reg */ -+ restore_reg(state, op->dest.reg); -+ } -+ -+ break; -+ -+ default: -+ WARN_FUNC("unknown stack-related instruction", -+ insn->sec, insn->offset); -+ return -1; - } - -- insn->visited = true; -- insn->state = state; -+ break; - -- list_for_each_entry(alt, &insn->alts, list) { -- ret = validate_branch(file, alt->insn, state); -- if (ret) -+ case OP_DEST_PUSH: -+ state->stack_size += 8; -+ if (cfa->base == CFI_SP) -+ cfa->offset += 8; -+ -+ if (op->src.type != OP_SRC_REG) -+ break; -+ -+ if (state->drap) { -+ if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { -+ -+ /* drap: push %drap */ -+ cfa->base = CFI_BP_INDIRECT; -+ cfa->offset = -state->stack_size; -+ -+ /* save drap so we know when to restore it */ -+ state->drap_offset = -state->stack_size; -+ -+ } else if (op->src.reg == CFI_BP && cfa->base == state->drap_reg) { -+ -+ /* drap: push %rbp */ -+ state->stack_size = 0; -+ -+ } else if (regs[op->src.reg].base == CFI_UNDEFINED) { -+ -+ /* drap: push %reg */ -+ save_reg(state, op->src.reg, CFI_BP, -state->stack_size); -+ } -+ -+ } else { -+ -+ /* push %reg */ -+ save_reg(state, op->src.reg, CFI_CFA, -state->stack_size); -+ } -+ -+ /* detect when asm code uses rbp as a scratch register */ -+ if (!no_fp && insn->func && op->src.reg == CFI_BP && -+ cfa->base != CFI_BP) -+ state->bp_scratch = true; -+ break; -+ -+ case OP_DEST_REG_INDIRECT: -+ -+ if (state->drap) { -+ if (op->src.reg == cfa->base && op->src.reg == state->drap_reg) { -+ -+ /* drap: mov %drap, disp(%rbp) */ -+ cfa->base = CFI_BP_INDIRECT; -+ cfa->offset = op->dest.offset; -+ -+ /* save drap offset so we know when to restore it */ -+ state->drap_offset = op->dest.offset; -+ } -+ -+ else if (regs[op->src.reg].base == CFI_UNDEFINED) { -+ -+ /* drap: mov reg, disp(%rbp) */ -+ save_reg(state, op->src.reg, CFI_BP, op->dest.offset); -+ } -+ -+ } else if (op->dest.reg == cfa->base) { -+ -+ /* mov reg, disp(%rbp) */ -+ /* mov reg, disp(%rsp) */ -+ save_reg(state, op->src.reg, CFI_CFA, -+ op->dest.offset - state->cfa.offset); -+ } -+ -+ break; -+ -+ case OP_DEST_LEAVE: -+ if ((!state->drap && cfa->base != CFI_BP) || -+ (state->drap && cfa->base != state->drap_reg)) { -+ WARN_FUNC("leave instruction with modified stack frame", -+ insn->sec, insn->offset); -+ return -1; -+ } -+ -+ /* leave (mov %rbp, %rsp; pop %rbp) */ -+ -+ state->stack_size = -state->regs[CFI_BP].offset - 8; -+ restore_reg(state, CFI_BP); -+ -+ if (!state->drap) { -+ cfa->base = CFI_SP; -+ cfa->offset -= 8; -+ } -+ -+ break; -+ -+ case OP_DEST_MEM: -+ if (op->src.type != OP_SRC_POP) { -+ WARN_FUNC("unknown stack-related memory operation", -+ insn->sec, insn->offset); -+ return -1; -+ } -+ -+ /* pop mem */ -+ state->stack_size -= 8; -+ if (cfa->base == CFI_SP) -+ cfa->offset -= 8; -+ -+ break; -+ -+ default: -+ WARN_FUNC("unknown stack-related instruction", -+ insn->sec, insn->offset); -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static bool insn_state_match(struct instruction *insn, struct insn_state *state) -+{ -+ struct insn_state *state1 = &insn->state, *state2 = state; -+ int i; -+ -+ if (memcmp(&state1->cfa, &state2->cfa, sizeof(state1->cfa))) { -+ WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d", -+ insn->sec, insn->offset, -+ state1->cfa.base, state1->cfa.offset, -+ state2->cfa.base, state2->cfa.offset); -+ -+ } else if (memcmp(&state1->regs, &state2->regs, sizeof(state1->regs))) { -+ for (i = 0; i < CFI_NUM_REGS; i++) { -+ if (!memcmp(&state1->regs[i], &state2->regs[i], -+ sizeof(struct cfi_reg))) -+ continue; -+ -+ WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", -+ insn->sec, insn->offset, -+ i, state1->regs[i].base, state1->regs[i].offset, -+ i, state2->regs[i].base, state2->regs[i].offset); -+ break; -+ } -+ -+ } else if (state1->type != state2->type) { -+ WARN_FUNC("stack state mismatch: type1=%d type2=%d", -+ insn->sec, insn->offset, state1->type, state2->type); -+ -+ } else if (state1->drap != state2->drap || -+ (state1->drap && state1->drap_reg != state2->drap_reg) || -+ (state1->drap && state1->drap_offset != state2->drap_offset)) { -+ WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", -+ insn->sec, insn->offset, -+ state1->drap, state1->drap_reg, state1->drap_offset, -+ state2->drap, state2->drap_reg, state2->drap_offset); -+ -+ } else -+ return true; -+ -+ return false; -+} -+ -+/* -+ * Follow the branch starting at the given instruction, and recursively follow -+ * any other branches (jumps). Meanwhile, track the frame pointer state at -+ * each instruction and validate all the rules described in -+ * tools/objtool/Documentation/stack-validation.txt. -+ */ -+static int validate_branch(struct objtool_file *file, struct instruction *first, -+ struct insn_state state) -+{ -+ struct alternative *alt; -+ struct instruction *insn, *next_insn; -+ struct section *sec; -+ struct symbol *func = NULL; -+ int ret; -+ -+ insn = first; -+ sec = insn->sec; -+ -+ if (insn->alt_group && list_empty(&insn->alts)) { -+ WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", -+ sec, insn->offset); -+ return 1; -+ } -+ -+ while (1) { -+ next_insn = next_insn_same_sec(file, insn); -+ -+ -+ if (file->c_file && func && insn->func && func != insn->func) { -+ WARN("%s() falls through to next function %s()", -+ func->name, insn->func->name); -+ return 1; -+ } -+ -+ if (insn->func) -+ func = insn->func; -+ -+ if (func && insn->ignore) { -+ WARN_FUNC("BUG: why am I validating an ignored function?", -+ sec, insn->offset); -+ return 1; -+ } -+ -+ if (insn->visited) { -+ if (!insn->hint && !insn_state_match(insn, &state)) - return 1; -+ -+ return 0; - } - -- switch (insn->type) { -+ if (insn->hint) { -+ if (insn->restore) { -+ struct instruction *save_insn, *i; -+ -+ i = insn; -+ save_insn = NULL; -+ func_for_each_insn_continue_reverse(file, func, i) { -+ if (i->save) { -+ save_insn = i; -+ break; -+ } -+ } - -- case INSN_FP_SAVE: -- if (!nofp) { -- if (state & STATE_FP_SAVED) { -- WARN_FUNC("duplicate frame pointer save", -+ if (!save_insn) { -+ WARN_FUNC("no corresponding CFI save for CFI restore", - sec, insn->offset); - return 1; - } -- state |= STATE_FP_SAVED; -- } -- break; - -- case INSN_FP_SETUP: -- if (!nofp) { -- if (state & STATE_FP_SETUP) { -- WARN_FUNC("duplicate frame pointer setup", -+ if (!save_insn->visited) { -+ /* -+ * Oops, no state to copy yet. -+ * Hopefully we can reach this -+ * instruction from another branch -+ * after the save insn has been -+ * visited. -+ */ -+ if (insn == first) -+ return 0; -+ -+ WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo", - sec, insn->offset); - return 1; - } -- state |= STATE_FP_SETUP; -+ -+ insn->state = save_insn->state; - } -- break; - -- case INSN_FP_RESTORE: -- if (!nofp) { -- if (has_valid_stack_frame(insn)) -- state &= ~STATE_FP_SETUP; -+ state = insn->state; -+ -+ } else -+ insn->state = state; -+ -+ insn->visited = true; - -- state &= ~STATE_FP_SAVED; -+ if (!insn->ignore_alts) { -+ list_for_each_entry(alt, &insn->alts, list) { -+ ret = validate_branch(file, alt->insn, state); -+ if (ret) -+ return 1; - } -- break; -+ } -+ -+ switch (insn->type) { - - case INSN_RETURN: -- if (!nofp && has_modified_stack_frame(insn)) { -- WARN_FUNC("return without frame pointer restore", -+ if (func && has_modified_stack_frame(&state)) { -+ WARN_FUNC("return with modified stack frame", - sec, insn->offset); - return 1; - } -+ -+ if (state.bp_scratch) { -+ WARN("%s uses BP as a scratch register", -+ insn->func->name); -+ return 1; -+ } -+ - return 0; - - case INSN_CALL: -- if (is_fentry_call(insn)) { -- state |= STATE_FENTRY; -+ if (is_fentry_call(insn)) - break; -- } - - ret = dead_end_function(file, insn->call_dest); - if (ret == 1) -@@ -1085,7 +1853,7 @@ static int validate_branch(struct objtool_file *file, - - /* fallthrough */ - case INSN_CALL_DYNAMIC: -- if (!nofp && !has_valid_stack_frame(insn)) { -+ if (!no_fp && func && !has_valid_stack_frame(&state)) { - WARN_FUNC("call without frame pointer save/setup", - sec, insn->offset); - return 1; -@@ -1094,16 +1862,19 @@ static int validate_branch(struct objtool_file *file, - - case INSN_JUMP_CONDITIONAL: - case INSN_JUMP_UNCONDITIONAL: -- if (insn->jump_dest) { -+ if (insn->jump_dest && -+ (!func || !insn->jump_dest->func || -+ func == insn->jump_dest->func)) { - ret = validate_branch(file, insn->jump_dest, - state); - if (ret) - return 1; -- } else if (has_modified_stack_frame(insn)) { -- WARN_FUNC("sibling call from callable instruction with changed frame pointer", -+ -+ } else if (func && has_modified_stack_frame(&state)) { -+ WARN_FUNC("sibling call from callable instruction with modified stack frame", - sec, insn->offset); - return 1; -- } /* else it's a sibling call */ -+ } - - if (insn->type == INSN_JUMP_UNCONDITIONAL) - return 0; -@@ -1111,15 +1882,29 @@ static int validate_branch(struct objtool_file *file, - break; - - case INSN_JUMP_DYNAMIC: -- if (list_empty(&insn->alts) && -- has_modified_stack_frame(insn)) { -- WARN_FUNC("sibling call from callable instruction with changed frame pointer", -+ if (func && list_empty(&insn->alts) && -+ has_modified_stack_frame(&state)) { -+ WARN_FUNC("sibling call from callable instruction with modified stack frame", - sec, insn->offset); - return 1; - } - - return 0; - -+ case INSN_CONTEXT_SWITCH: -+ if (func && (!next_insn || !next_insn->hint)) { -+ WARN_FUNC("unsupported instruction in callable function", -+ sec, insn->offset); -+ return 1; -+ } -+ return 0; -+ -+ case INSN_STACK: -+ if (update_insn_state(insn, &state)) -+ return 1; -+ -+ break; -+ - default: - break; - } -@@ -1127,16 +1912,72 @@ static int validate_branch(struct objtool_file *file, - if (insn->dead_end) - return 0; - -- insn = next_insn_same_sec(file, insn); -- if (!insn) { -+ if (!next_insn) { -+ if (state.cfa.base == CFI_UNDEFINED) -+ return 0; - WARN("%s: unexpected end of section", sec->name); - return 1; - } -+ -+ insn = next_insn; - } - - return 0; - } - -+static int validate_unwind_hints(struct objtool_file *file) -+{ -+ struct instruction *insn; -+ int ret, warnings = 0; -+ struct insn_state state; -+ -+ if (!file->hints) -+ return 0; -+ -+ clear_insn_state(&state); -+ -+ for_each_insn(file, insn) { -+ if (insn->hint && !insn->visited) { -+ ret = validate_branch(file, insn, state); -+ warnings += ret; -+ } -+ } -+ -+ return warnings; -+} -+ -+static int validate_retpoline(struct objtool_file *file) -+{ -+ struct instruction *insn; -+ int warnings = 0; -+ -+ for_each_insn(file, insn) { -+ if (insn->type != INSN_JUMP_DYNAMIC && -+ insn->type != INSN_CALL_DYNAMIC) -+ continue; -+ -+ if (insn->retpoline_safe) -+ continue; -+ -+ /* -+ * .init.text code is ran before userspace and thus doesn't -+ * strictly need retpolines, except for modules which are -+ * loaded late, they very much do need retpoline in their -+ * .init.text -+ */ -+ if (!strcmp(insn->sec->name, ".init.text") && !module) -+ continue; -+ -+ WARN_FUNC("indirect %s found in RETPOLINE build", -+ insn->sec, insn->offset, -+ insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); -+ -+ warnings++; -+ } -+ -+ return warnings; -+} -+ - static bool is_kasan_insn(struct instruction *insn) - { - return (insn->type == INSN_CALL && -@@ -1150,12 +1991,23 @@ static bool is_ubsan_insn(struct instruction *insn) - "__ubsan_handle_builtin_unreachable")); - } - --static bool ignore_unreachable_insn(struct symbol *func, -- struct instruction *insn) -+static bool ignore_unreachable_insn(struct instruction *insn) - { - int i; - -- if (insn->type == INSN_NOP) -+ if (insn->ignore || insn->type == INSN_NOP) -+ return true; -+ -+ /* -+ * Ignore any unused exceptions. This can happen when a whitelisted -+ * function has an exception table entry. -+ * -+ * Also ignore alternative replacement instructions. This can happen -+ * when a whitelisted function uses one of the ALTERNATIVE macros. -+ */ -+ if (!strcmp(insn->sec->name, ".fixup") || -+ !strcmp(insn->sec->name, ".altinstr_replacement") || -+ !strcmp(insn->sec->name, ".altinstr_aux")) - return true; - - /* -@@ -1164,18 +2016,26 @@ static bool ignore_unreachable_insn(struct symbol *func, - * - * End the search at 5 instructions to avoid going into the weeds. - */ -+ if (!insn->func) -+ return false; - for (i = 0; i < 5; i++) { - - if (is_kasan_insn(insn) || is_ubsan_insn(insn)) - return true; - -- if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { -- insn = insn->jump_dest; -- continue; -+ if (insn->type == INSN_JUMP_UNCONDITIONAL) { -+ if (insn->jump_dest && -+ insn->jump_dest->func == insn->func) { -+ insn = insn->jump_dest; -+ continue; -+ } -+ -+ break; - } - -- if (insn->offset + insn->len >= func->offset + func->len) -+ if (insn->offset + insn->len >= insn->func->offset + insn->func->len) - break; -+ - insn = list_next_entry(insn, list); - } - -@@ -1187,81 +2047,49 @@ static int validate_functions(struct objtool_file *file) - struct section *sec; - struct symbol *func; - struct instruction *insn; -+ struct insn_state state; - int ret, warnings = 0; - -- list_for_each_entry(sec, &file->elf->sections, list) { -+ clear_insn_state(&state); -+ -+ state.cfa = initial_func_cfi.cfa; -+ memcpy(&state.regs, &initial_func_cfi.regs, -+ CFI_NUM_REGS * sizeof(struct cfi_reg)); -+ state.stack_size = initial_func_cfi.cfa.offset; -+ -+ for_each_sec(file, sec) { - list_for_each_entry(func, &sec->symbol_list, list) { - if (func->type != STT_FUNC) - continue; - - insn = find_insn(file, sec, func->offset); -- if (!insn) -+ if (!insn || insn->ignore) - continue; - -- ret = validate_branch(file, insn, 0); -+ ret = validate_branch(file, insn, state); - warnings += ret; - } - } - -- list_for_each_entry(sec, &file->elf->sections, list) { -- list_for_each_entry(func, &sec->symbol_list, list) { -- if (func->type != STT_FUNC) -- continue; -- -- func_for_each_insn(file, func, insn) { -- if (insn->visited) -- continue; -- -- insn->visited = true; -- -- if (file->ignore_unreachables || warnings || -- ignore_unreachable_insn(func, insn)) -- continue; -- -- /* -- * gcov produces a lot of unreachable -- * instructions. If we get an unreachable -- * warning and the file has gcov enabled, just -- * ignore it, and all other such warnings for -- * the file. -- */ -- if (!file->ignore_unreachables && -- gcov_enabled(file)) { -- file->ignore_unreachables = true; -- continue; -- } -- -- WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); -- warnings++; -- } -- } -- } -- - return warnings; - } - --static int validate_uncallable_instructions(struct objtool_file *file) -+static int validate_reachable_instructions(struct objtool_file *file) - { - struct instruction *insn; -- int warnings = 0; - -- for_each_insn(file, insn) { -- if (!insn->visited && insn->type == INSN_RETURN) { -+ if (file->ignore_unreachables) -+ return 0; - -- /* -- * Don't warn about call instructions in unvisited -- * retpoline alternatives. -- */ -- if (!strcmp(insn->sec->name, ".altinstr_replacement")) -- continue; -+ for_each_insn(file, insn) { -+ if (insn->visited || ignore_unreachable_insn(insn)) -+ continue; - -- WARN_FUNC("return instruction outside of a callable function", -- insn->sec, insn->offset); -- warnings++; -- } -+ WARN_FUNC("unreachable instruction", insn->sec, insn->offset); -+ return 1; - } - -- return warnings; -+ return 0; - } - - static void cleanup(struct objtool_file *file) -@@ -1281,42 +2109,73 @@ static void cleanup(struct objtool_file *file) - elf_close(file->elf); - } - --int check(const char *_objname, bool _nofp) -+int check(const char *_objname, bool orc) - { - struct objtool_file file; - int ret, warnings = 0; - - objname = _objname; -- nofp = _nofp; - -- file.elf = elf_open(objname); -- if (!file.elf) { -- fprintf(stderr, "error reading elf file %s\n", objname); -+ file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); -+ if (!file.elf) - return 1; -- } - - INIT_LIST_HEAD(&file.insn_list); - hash_init(file.insn_hash); - file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); - file.rodata = find_section_by_name(file.elf, ".rodata"); -- file.ignore_unreachables = false; - file.c_file = find_section_by_name(file.elf, ".comment"); -+ file.ignore_unreachables = no_unreachable; -+ file.hints = false; -+ -+ arch_initial_func_cfi_state(&initial_func_cfi); - - ret = decode_sections(&file); - if (ret < 0) - goto out; - warnings += ret; - -+ if (list_empty(&file.insn_list)) -+ goto out; -+ -+ if (retpoline) { -+ ret = validate_retpoline(&file); -+ if (ret < 0) -+ return ret; -+ warnings += ret; -+ } -+ - ret = validate_functions(&file); - if (ret < 0) - goto out; - warnings += ret; - -- ret = validate_uncallable_instructions(&file); -+ ret = validate_unwind_hints(&file); - if (ret < 0) - goto out; - warnings += ret; - -+ if (!warnings) { -+ ret = validate_reachable_instructions(&file); -+ if (ret < 0) -+ goto out; -+ warnings += ret; -+ } -+ -+ if (orc) { -+ ret = create_orc(&file); -+ if (ret < 0) -+ goto out; -+ -+ ret = create_orc_sections(&file); -+ if (ret < 0) -+ goto out; -+ -+ ret = elf_write(file.elf); -+ if (ret < 0) -+ goto out; -+ } -+ - out: - cleanup(&file); - -diff --git a/tools/objtool/check.h b/tools/objtool/check.h -index aca248a..c6b68fc 100644 ---- a/tools/objtool/check.h -+++ b/tools/objtool/check.h -@@ -20,22 +20,40 @@ - - #include <stdbool.h> - #include "elf.h" -+#include "cfi.h" - #include "arch.h" -+#include "orc.h" - #include <linux/hashtable.h> - -+struct insn_state { -+ struct cfi_reg cfa; -+ struct cfi_reg regs[CFI_NUM_REGS]; -+ int stack_size; -+ unsigned char type; -+ bool bp_scratch; -+ bool drap; -+ int drap_reg, drap_offset; -+ struct cfi_reg vals[CFI_NUM_REGS]; -+}; -+ - struct instruction { - struct list_head list; - struct hlist_node hash; - struct section *sec; - unsigned long offset; -- unsigned int len, state; -+ unsigned int len; - unsigned char type; - unsigned long immediate; -- bool alt_group, visited, dead_end, ignore_alts; -+ bool alt_group, visited, dead_end, ignore, hint, save, restore, ignore_alts; -+ bool retpoline_safe; - struct symbol *call_dest; - struct instruction *jump_dest; -+ struct instruction *first_jump_src; - struct list_head alts; - struct symbol *func; -+ struct stack_op stack_op; -+ struct insn_state state; -+ struct orc_entry orc; - }; - - struct objtool_file { -@@ -43,9 +61,22 @@ struct objtool_file { - struct list_head insn_list; - DECLARE_HASHTABLE(insn_hash, 16); - struct section *rodata, *whitelist; -- bool ignore_unreachables, c_file; -+ bool ignore_unreachables, c_file, hints; - }; - --int check(const char *objname, bool nofp); -+int check(const char *objname, bool orc); -+ -+struct instruction *find_insn(struct objtool_file *file, -+ struct section *sec, unsigned long offset); -+ -+#define for_each_insn(file, insn) \ -+ list_for_each_entry(insn, &file->insn_list, list) -+ -+#define sec_for_each_insn(file, sec, insn) \ -+ for (insn = find_insn(file, sec, 0); \ -+ insn && &insn->list != &file->insn_list && \ -+ insn->sec == sec; \ -+ insn = list_next_entry(insn, list)) -+ - - #endif /* _CHECK_H */ -diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c -index 14a74d4..b31b7a6 100644 ---- a/tools/objtool/elf.c -+++ b/tools/objtool/elf.c -@@ -31,13 +31,6 @@ - #include "elf.h" - #include "warn.h" - --/* -- * Fallback for systems without this "read, mmaping if possible" cmd. -- */ --#ifndef ELF_C_READ_MMAP --#define ELF_C_READ_MMAP ELF_C_READ --#endif -- - struct section *find_section_by_name(struct elf *elf, const char *name) - { - struct section *sec; -@@ -128,12 +121,12 @@ static int read_sections(struct elf *elf) - int i; - - if (elf_getshdrnum(elf->elf, §ions_nr)) { -- perror("elf_getshdrnum"); -+ WARN_ELF("elf_getshdrnum"); - return -1; - } - - if (elf_getshdrstrndx(elf->elf, &shstrndx)) { -- perror("elf_getshdrstrndx"); -+ WARN_ELF("elf_getshdrstrndx"); - return -1; - } - -@@ -154,37 +147,37 @@ static int read_sections(struct elf *elf) - - s = elf_getscn(elf->elf, i); - if (!s) { -- perror("elf_getscn"); -+ WARN_ELF("elf_getscn"); - return -1; - } - - sec->idx = elf_ndxscn(s); - - if (!gelf_getshdr(s, &sec->sh)) { -- perror("gelf_getshdr"); -+ WARN_ELF("gelf_getshdr"); - return -1; - } - - sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); - if (!sec->name) { -- perror("elf_strptr"); -- return -1; -- } -- -- sec->elf_data = elf_getdata(s, NULL); -- if (!sec->elf_data) { -- perror("elf_getdata"); -+ WARN_ELF("elf_strptr"); - return -1; - } - -- if (sec->elf_data->d_off != 0 || -- sec->elf_data->d_size != sec->sh.sh_size) { -- WARN("unexpected data attributes for %s", sec->name); -- return -1; -+ if (sec->sh.sh_size != 0) { -+ sec->data = elf_getdata(s, NULL); -+ if (!sec->data) { -+ WARN_ELF("elf_getdata"); -+ return -1; -+ } -+ if (sec->data->d_off != 0 || -+ sec->data->d_size != sec->sh.sh_size) { -+ WARN("unexpected data attributes for %s", -+ sec->name); -+ return -1; -+ } - } -- -- sec->data = (unsigned long)sec->elf_data->d_buf; -- sec->len = sec->elf_data->d_size; -+ sec->len = sec->sh.sh_size; - } - - /* sanity check, one more call to elf_nextscn() should return NULL */ -@@ -221,15 +214,15 @@ static int read_symbols(struct elf *elf) - - sym->idx = i; - -- if (!gelf_getsym(symtab->elf_data, i, &sym->sym)) { -- perror("gelf_getsym"); -+ if (!gelf_getsym(symtab->data, i, &sym->sym)) { -+ WARN_ELF("gelf_getsym"); - goto err; - } - - sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, - sym->sym.st_name); - if (!sym->name) { -- perror("elf_strptr"); -+ WARN_ELF("elf_strptr"); - goto err; - } - -@@ -311,8 +304,8 @@ static int read_relas(struct elf *elf) - } - memset(rela, 0, sizeof(*rela)); - -- if (!gelf_getrela(sec->elf_data, i, &rela->rela)) { -- perror("gelf_getrela"); -+ if (!gelf_getrela(sec->data, i, &rela->rela)) { -+ WARN_ELF("gelf_getrela"); - return -1; - } - -@@ -336,9 +329,10 @@ static int read_relas(struct elf *elf) - return 0; - } - --struct elf *elf_open(const char *name) -+struct elf *elf_open(const char *name, int flags) - { - struct elf *elf; -+ Elf_Cmd cmd; - - elf_version(EV_CURRENT); - -@@ -351,27 +345,28 @@ struct elf *elf_open(const char *name) - - INIT_LIST_HEAD(&elf->sections); - -- elf->name = strdup(name); -- if (!elf->name) { -- perror("strdup"); -- goto err; -- } -- -- elf->fd = open(name, O_RDONLY); -+ elf->fd = open(name, flags); - if (elf->fd == -1) { - fprintf(stderr, "objtool: Can't open '%s': %s\n", - name, strerror(errno)); - goto err; - } - -- elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); -+ if ((flags & O_ACCMODE) == O_RDONLY) -+ cmd = ELF_C_READ_MMAP; -+ else if ((flags & O_ACCMODE) == O_RDWR) -+ cmd = ELF_C_RDWR; -+ else /* O_WRONLY */ -+ cmd = ELF_C_WRITE; -+ -+ elf->elf = elf_begin(elf->fd, cmd, NULL); - if (!elf->elf) { -- perror("elf_begin"); -+ WARN_ELF("elf_begin"); - goto err; - } - - if (!gelf_getehdr(elf->elf, &elf->ehdr)) { -- perror("gelf_getehdr"); -+ WARN_ELF("gelf_getehdr"); - goto err; - } - -@@ -391,12 +386,212 @@ struct elf *elf_open(const char *name) - return NULL; - } - -+struct section *elf_create_section(struct elf *elf, const char *name, -+ size_t entsize, int nr) -+{ -+ struct section *sec, *shstrtab; -+ size_t size = entsize * nr; -+ struct Elf_Scn *s; -+ Elf_Data *data; -+ -+ sec = malloc(sizeof(*sec)); -+ if (!sec) { -+ perror("malloc"); -+ return NULL; -+ } -+ memset(sec, 0, sizeof(*sec)); -+ -+ INIT_LIST_HEAD(&sec->symbol_list); -+ INIT_LIST_HEAD(&sec->rela_list); -+ hash_init(sec->rela_hash); -+ hash_init(sec->symbol_hash); -+ -+ list_add_tail(&sec->list, &elf->sections); -+ -+ s = elf_newscn(elf->elf); -+ if (!s) { -+ WARN_ELF("elf_newscn"); -+ return NULL; -+ } -+ -+ sec->name = strdup(name); -+ if (!sec->name) { -+ perror("strdup"); -+ return NULL; -+ } -+ -+ sec->idx = elf_ndxscn(s); -+ sec->len = size; -+ sec->changed = true; -+ -+ sec->data = elf_newdata(s); -+ if (!sec->data) { -+ WARN_ELF("elf_newdata"); -+ return NULL; -+ } -+ -+ sec->data->d_size = size; -+ sec->data->d_align = 1; -+ -+ if (size) { -+ sec->data->d_buf = malloc(size); -+ if (!sec->data->d_buf) { -+ perror("malloc"); -+ return NULL; -+ } -+ memset(sec->data->d_buf, 0, size); -+ } -+ -+ if (!gelf_getshdr(s, &sec->sh)) { -+ WARN_ELF("gelf_getshdr"); -+ return NULL; -+ } -+ -+ sec->sh.sh_size = size; -+ sec->sh.sh_entsize = entsize; -+ sec->sh.sh_type = SHT_PROGBITS; -+ sec->sh.sh_addralign = 1; -+ sec->sh.sh_flags = SHF_ALLOC; -+ -+ -+ /* Add section name to .shstrtab */ -+ shstrtab = find_section_by_name(elf, ".shstrtab"); -+ if (!shstrtab) { -+ WARN("can't find .shstrtab section"); -+ return NULL; -+ } -+ -+ s = elf_getscn(elf->elf, shstrtab->idx); -+ if (!s) { -+ WARN_ELF("elf_getscn"); -+ return NULL; -+ } -+ -+ data = elf_newdata(s); -+ if (!data) { -+ WARN_ELF("elf_newdata"); -+ return NULL; -+ } -+ -+ data->d_buf = sec->name; -+ data->d_size = strlen(name) + 1; -+ data->d_align = 1; -+ -+ sec->sh.sh_name = shstrtab->len; -+ -+ shstrtab->len += strlen(name) + 1; -+ shstrtab->changed = true; -+ -+ return sec; -+} -+ -+struct section *elf_create_rela_section(struct elf *elf, struct section *base) -+{ -+ char *relaname; -+ struct section *sec; -+ -+ relaname = malloc(strlen(base->name) + strlen(".rela") + 1); -+ if (!relaname) { -+ perror("malloc"); -+ return NULL; -+ } -+ strcpy(relaname, ".rela"); -+ strcat(relaname, base->name); -+ -+ sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); -+ free(relaname); -+ if (!sec) -+ return NULL; -+ -+ base->rela = sec; -+ sec->base = base; -+ -+ sec->sh.sh_type = SHT_RELA; -+ sec->sh.sh_addralign = 8; -+ sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; -+ sec->sh.sh_info = base->idx; -+ sec->sh.sh_flags = SHF_INFO_LINK; -+ -+ return sec; -+} -+ -+int elf_rebuild_rela_section(struct section *sec) -+{ -+ struct rela *rela; -+ int nr, idx = 0, size; -+ GElf_Rela *relas; -+ -+ nr = 0; -+ list_for_each_entry(rela, &sec->rela_list, list) -+ nr++; -+ -+ size = nr * sizeof(*relas); -+ relas = malloc(size); -+ if (!relas) { -+ perror("malloc"); -+ return -1; -+ } -+ -+ sec->data->d_buf = relas; -+ sec->data->d_size = size; -+ -+ sec->sh.sh_size = size; -+ -+ idx = 0; -+ list_for_each_entry(rela, &sec->rela_list, list) { -+ relas[idx].r_offset = rela->offset; -+ relas[idx].r_addend = rela->addend; -+ relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type); -+ idx++; -+ } -+ -+ return 0; -+} -+ -+int elf_write(struct elf *elf) -+{ -+ struct section *sec; -+ Elf_Scn *s; -+ -+ /* Update section headers for changed sections: */ -+ list_for_each_entry(sec, &elf->sections, list) { -+ if (sec->changed) { -+ s = elf_getscn(elf->elf, sec->idx); -+ if (!s) { -+ WARN_ELF("elf_getscn"); -+ return -1; -+ } -+ if (!gelf_update_shdr(s, &sec->sh)) { -+ WARN_ELF("gelf_update_shdr"); -+ return -1; -+ } -+ } -+ } -+ -+ /* Make sure the new section header entries get updated properly. */ -+ elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY); -+ -+ /* Write all changes to the file. */ -+ if (elf_update(elf->elf, ELF_C_WRITE) < 0) { -+ WARN_ELF("elf_update"); -+ return -1; -+ } -+ -+ return 0; -+} -+ - void elf_close(struct elf *elf) - { - struct section *sec, *tmpsec; - struct symbol *sym, *tmpsym; - struct rela *rela, *tmprela; - -+ if (elf->elf) -+ elf_end(elf->elf); -+ -+ if (elf->fd > 0) -+ close(elf->fd); -+ - list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { - list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) { - list_del(&sym->list); -@@ -411,11 +606,6 @@ void elf_close(struct elf *elf) - list_del(&sec->list); - free(sec); - } -- if (elf->name) -- free(elf->name); -- if (elf->fd > 0) -- close(elf->fd); -- if (elf->elf) -- elf_end(elf->elf); -+ - free(elf); - } -diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h -index aa1ff65..440b83b 100644 ---- a/tools/objtool/elf.h -+++ b/tools/objtool/elf.h -@@ -28,6 +28,13 @@ - # define elf_getshdrstrndx elf_getshstrndx - #endif - -+/* -+ * Fallback for systems without this "read, mmaping if possible" cmd. -+ */ -+#ifndef ELF_C_READ_MMAP -+#define ELF_C_READ_MMAP ELF_C_READ -+#endif -+ - struct section { - struct list_head list; - GElf_Shdr sh; -@@ -37,11 +44,11 @@ struct section { - DECLARE_HASHTABLE(rela_hash, 16); - struct section *base, *rela; - struct symbol *sym; -- Elf_Data *elf_data; -+ Elf_Data *data; - char *name; - int idx; -- unsigned long data; - unsigned int len; -+ bool changed, text; - }; - - struct symbol { -@@ -76,15 +83,21 @@ struct elf { - }; - - --struct elf *elf_open(const char *name); -+struct elf *elf_open(const char *name, int flags); - struct section *find_section_by_name(struct elf *elf, const char *name); - struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); - struct rela *find_rela_by_dest(struct section *sec, unsigned long offset); - struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, - unsigned int len); - struct symbol *find_containing_func(struct section *sec, unsigned long offset); -+struct section *elf_create_section(struct elf *elf, const char *name, size_t -+ entsize, int nr); -+struct section *elf_create_rela_section(struct elf *elf, struct section *base); -+int elf_rebuild_rela_section(struct section *sec); -+int elf_write(struct elf *elf); - void elf_close(struct elf *elf); - -- -+#define for_each_sec(file, sec) \ -+ list_for_each_entry(sec, &file->elf->sections, list) - - #endif /* _OBJTOOL_ELF_H */ -diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c -index 46c326d..07f3299 100644 ---- a/tools/objtool/objtool.c -+++ b/tools/objtool/objtool.c -@@ -31,11 +31,10 @@ - #include <stdlib.h> - #include <subcmd/exec-cmd.h> - #include <subcmd/pager.h> -+#include <linux/kernel.h> - - #include "builtin.h" - --#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -- - struct cmd_struct { - const char *name; - int (*fn)(int, const char **); -@@ -43,10 +42,11 @@ struct cmd_struct { - }; - - static const char objtool_usage_string[] = -- "objtool [OPTIONS] COMMAND [ARGS]"; -+ "objtool COMMAND [ARGS]"; - - static struct cmd_struct objtool_cmds[] = { - {"check", cmd_check, "Perform stack metadata validation on an object file" }, -+ {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" }, - }; - - bool help; -@@ -70,7 +70,7 @@ static void cmd_usage(void) - - printf("\n"); - -- exit(1); -+ exit(129); - } - - static void handle_options(int *argc, const char ***argv) -@@ -86,9 +86,7 @@ static void handle_options(int *argc, const char ***argv) - break; - } else { - fprintf(stderr, "Unknown option: %s\n", cmd); -- fprintf(stderr, "\n Usage: %s\n", -- objtool_usage_string); -- exit(1); -+ cmd_usage(); - } - - (*argv)++; -diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h -new file mode 100644 -index 0000000..b0e92a6 ---- /dev/null -+++ b/tools/objtool/orc.h -@@ -0,0 +1,30 @@ -+/* -+ * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#ifndef _ORC_H -+#define _ORC_H -+ -+#include <asm/orc_types.h> -+ -+struct objtool_file; -+ -+int create_orc(struct objtool_file *file); -+int create_orc_sections(struct objtool_file *file); -+ -+int orc_dump(const char *objname); -+ -+#endif /* _ORC_H */ -diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c -new file mode 100644 -index 0000000..c334382 ---- /dev/null -+++ b/tools/objtool/orc_dump.c -@@ -0,0 +1,213 @@ -+/* -+ * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#include <unistd.h> -+#include "orc.h" -+#include "warn.h" -+ -+static const char *reg_name(unsigned int reg) -+{ -+ switch (reg) { -+ case ORC_REG_PREV_SP: -+ return "prevsp"; -+ case ORC_REG_DX: -+ return "dx"; -+ case ORC_REG_DI: -+ return "di"; -+ case ORC_REG_BP: -+ return "bp"; -+ case ORC_REG_SP: -+ return "sp"; -+ case ORC_REG_R10: -+ return "r10"; -+ case ORC_REG_R13: -+ return "r13"; -+ case ORC_REG_BP_INDIRECT: -+ return "bp(ind)"; -+ case ORC_REG_SP_INDIRECT: -+ return "sp(ind)"; -+ default: -+ return "?"; -+ } -+} -+ -+static const char *orc_type_name(unsigned int type) -+{ -+ switch (type) { -+ case ORC_TYPE_CALL: -+ return "call"; -+ case ORC_TYPE_REGS: -+ return "regs"; -+ case ORC_TYPE_REGS_IRET: -+ return "iret"; -+ default: -+ return "?"; -+ } -+} -+ -+static void print_reg(unsigned int reg, int offset) -+{ -+ if (reg == ORC_REG_BP_INDIRECT) -+ printf("(bp%+d)", offset); -+ else if (reg == ORC_REG_SP_INDIRECT) -+ printf("(sp%+d)", offset); -+ else if (reg == ORC_REG_UNDEFINED) -+ printf("(und)"); -+ else -+ printf("%s%+d", reg_name(reg), offset); -+} -+ -+int orc_dump(const char *_objname) -+{ -+ int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0; -+ struct orc_entry *orc = NULL; -+ char *name; -+ size_t nr_sections; -+ Elf64_Addr orc_ip_addr = 0; -+ size_t shstrtab_idx; -+ Elf *elf; -+ Elf_Scn *scn; -+ GElf_Shdr sh; -+ GElf_Rela rela; -+ GElf_Sym sym; -+ Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL; -+ -+ -+ objname = _objname; -+ -+ elf_version(EV_CURRENT); -+ -+ fd = open(objname, O_RDONLY); -+ if (fd == -1) { -+ perror("open"); -+ return -1; -+ } -+ -+ elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); -+ if (!elf) { -+ WARN_ELF("elf_begin"); -+ return -1; -+ } -+ -+ if (elf_getshdrnum(elf, &nr_sections)) { -+ WARN_ELF("elf_getshdrnum"); -+ return -1; -+ } -+ -+ if (elf_getshdrstrndx(elf, &shstrtab_idx)) { -+ WARN_ELF("elf_getshdrstrndx"); -+ return -1; -+ } -+ -+ for (i = 0; i < nr_sections; i++) { -+ scn = elf_getscn(elf, i); -+ if (!scn) { -+ WARN_ELF("elf_getscn"); -+ return -1; -+ } -+ -+ if (!gelf_getshdr(scn, &sh)) { -+ WARN_ELF("gelf_getshdr"); -+ return -1; -+ } -+ -+ name = elf_strptr(elf, shstrtab_idx, sh.sh_name); -+ if (!name) { -+ WARN_ELF("elf_strptr"); -+ return -1; -+ } -+ -+ data = elf_getdata(scn, NULL); -+ if (!data) { -+ WARN_ELF("elf_getdata"); -+ return -1; -+ } -+ -+ if (!strcmp(name, ".symtab")) { -+ symtab = data; -+ } else if (!strcmp(name, ".orc_unwind")) { -+ orc = data->d_buf; -+ orc_size = sh.sh_size; -+ } else if (!strcmp(name, ".orc_unwind_ip")) { -+ orc_ip = data->d_buf; -+ orc_ip_addr = sh.sh_addr; -+ } else if (!strcmp(name, ".rela.orc_unwind_ip")) { -+ rela_orc_ip = data; -+ } -+ } -+ -+ if (!symtab || !orc || !orc_ip) -+ return 0; -+ -+ if (orc_size % sizeof(*orc) != 0) { -+ WARN("bad .orc_unwind section size"); -+ return -1; -+ } -+ -+ nr_entries = orc_size / sizeof(*orc); -+ for (i = 0; i < nr_entries; i++) { -+ if (rela_orc_ip) { -+ if (!gelf_getrela(rela_orc_ip, i, &rela)) { -+ WARN_ELF("gelf_getrela"); -+ return -1; -+ } -+ -+ if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) { -+ WARN_ELF("gelf_getsym"); -+ return -1; -+ } -+ -+ scn = elf_getscn(elf, sym.st_shndx); -+ if (!scn) { -+ WARN_ELF("elf_getscn"); -+ return -1; -+ } -+ -+ if (!gelf_getshdr(scn, &sh)) { -+ WARN_ELF("gelf_getshdr"); -+ return -1; -+ } -+ -+ name = elf_strptr(elf, shstrtab_idx, sh.sh_name); -+ if (!name || !*name) { -+ WARN_ELF("elf_strptr"); -+ return -1; -+ } -+ -+ printf("%s+%llx:", name, (unsigned long long)rela.r_addend); -+ -+ } else { -+ printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i])); -+ } -+ -+ -+ printf(" sp:"); -+ -+ print_reg(orc[i].sp_reg, orc[i].sp_offset); -+ -+ printf(" bp:"); -+ -+ print_reg(orc[i].bp_reg, orc[i].bp_offset); -+ -+ printf(" type:%s\n", orc_type_name(orc[i].type)); -+ } -+ -+ elf_end(elf); -+ close(fd); -+ -+ return 0; -+} -diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c -new file mode 100644 -index 0000000..18384d9 ---- /dev/null -+++ b/tools/objtool/orc_gen.c -@@ -0,0 +1,221 @@ -+/* -+ * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see <http://www.gnu.org/licenses/>. -+ */ -+ -+#include <stdlib.h> -+#include <string.h> -+ -+#include "orc.h" -+#include "check.h" -+#include "warn.h" -+ -+int create_orc(struct objtool_file *file) -+{ -+ struct instruction *insn; -+ -+ for_each_insn(file, insn) { -+ struct orc_entry *orc = &insn->orc; -+ struct cfi_reg *cfa = &insn->state.cfa; -+ struct cfi_reg *bp = &insn->state.regs[CFI_BP]; -+ -+ if (cfa->base == CFI_UNDEFINED) { -+ orc->sp_reg = ORC_REG_UNDEFINED; -+ continue; -+ } -+ -+ switch (cfa->base) { -+ case CFI_SP: -+ orc->sp_reg = ORC_REG_SP; -+ break; -+ case CFI_SP_INDIRECT: -+ orc->sp_reg = ORC_REG_SP_INDIRECT; -+ break; -+ case CFI_BP: -+ orc->sp_reg = ORC_REG_BP; -+ break; -+ case CFI_BP_INDIRECT: -+ orc->sp_reg = ORC_REG_BP_INDIRECT; -+ break; -+ case CFI_R10: -+ orc->sp_reg = ORC_REG_R10; -+ break; -+ case CFI_R13: -+ orc->sp_reg = ORC_REG_R13; -+ break; -+ case CFI_DI: -+ orc->sp_reg = ORC_REG_DI; -+ break; -+ case CFI_DX: -+ orc->sp_reg = ORC_REG_DX; -+ break; -+ default: -+ WARN_FUNC("unknown CFA base reg %d", -+ insn->sec, insn->offset, cfa->base); -+ return -1; -+ } -+ -+ switch(bp->base) { -+ case CFI_UNDEFINED: -+ orc->bp_reg = ORC_REG_UNDEFINED; -+ break; -+ case CFI_CFA: -+ orc->bp_reg = ORC_REG_PREV_SP; -+ break; -+ case CFI_BP: -+ orc->bp_reg = ORC_REG_BP; -+ break; -+ default: -+ WARN_FUNC("unknown BP base reg %d", -+ insn->sec, insn->offset, bp->base); -+ return -1; -+ } -+ -+ orc->sp_offset = cfa->offset; -+ orc->bp_offset = bp->offset; -+ orc->type = insn->state.type; -+ } -+ -+ return 0; -+} -+ -+static int create_orc_entry(struct section *u_sec, struct section *ip_relasec, -+ unsigned int idx, struct section *insn_sec, -+ unsigned long insn_off, struct orc_entry *o) -+{ -+ struct orc_entry *orc; -+ struct rela *rela; -+ -+ if (!insn_sec->sym) { -+ WARN("missing symbol for section %s", insn_sec->name); -+ return -1; -+ } -+ -+ /* populate ORC data */ -+ orc = (struct orc_entry *)u_sec->data->d_buf + idx; -+ memcpy(orc, o, sizeof(*orc)); -+ -+ /* populate rela for ip */ -+ rela = malloc(sizeof(*rela)); -+ if (!rela) { -+ perror("malloc"); -+ return -1; -+ } -+ memset(rela, 0, sizeof(*rela)); -+ -+ rela->sym = insn_sec->sym; -+ rela->addend = insn_off; -+ rela->type = R_X86_64_PC32; -+ rela->offset = idx * sizeof(int); -+ -+ list_add_tail(&rela->list, &ip_relasec->rela_list); -+ hash_add(ip_relasec->rela_hash, &rela->hash, rela->offset); -+ -+ return 0; -+} -+ -+int create_orc_sections(struct objtool_file *file) -+{ -+ struct instruction *insn, *prev_insn; -+ struct section *sec, *u_sec, *ip_relasec; -+ unsigned int idx; -+ -+ struct orc_entry empty = { -+ .sp_reg = ORC_REG_UNDEFINED, -+ .bp_reg = ORC_REG_UNDEFINED, -+ .type = ORC_TYPE_CALL, -+ }; -+ -+ sec = find_section_by_name(file->elf, ".orc_unwind"); -+ if (sec) { -+ WARN("file already has .orc_unwind section, skipping"); -+ return -1; -+ } -+ -+ /* count the number of needed orcs */ -+ idx = 0; -+ for_each_sec(file, sec) { -+ if (!sec->text) -+ continue; -+ -+ prev_insn = NULL; -+ sec_for_each_insn(file, sec, insn) { -+ if (!prev_insn || -+ memcmp(&insn->orc, &prev_insn->orc, -+ sizeof(struct orc_entry))) { -+ idx++; -+ } -+ prev_insn = insn; -+ } -+ -+ /* section terminator */ -+ if (prev_insn) -+ idx++; -+ } -+ if (!idx) -+ return -1; -+ -+ -+ /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */ -+ sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx); -+ if (!sec) -+ return -1; -+ -+ ip_relasec = elf_create_rela_section(file->elf, sec); -+ if (!ip_relasec) -+ return -1; -+ -+ /* create .orc_unwind section */ -+ u_sec = elf_create_section(file->elf, ".orc_unwind", -+ sizeof(struct orc_entry), idx); -+ -+ /* populate sections */ -+ idx = 0; -+ for_each_sec(file, sec) { -+ if (!sec->text) -+ continue; -+ -+ prev_insn = NULL; -+ sec_for_each_insn(file, sec, insn) { -+ if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc, -+ sizeof(struct orc_entry))) { -+ -+ if (create_orc_entry(u_sec, ip_relasec, idx, -+ insn->sec, insn->offset, -+ &insn->orc)) -+ return -1; -+ -+ idx++; -+ } -+ prev_insn = insn; -+ } -+ -+ /* section terminator */ -+ if (prev_insn) { -+ if (create_orc_entry(u_sec, ip_relasec, idx, -+ prev_insn->sec, -+ prev_insn->offset + prev_insn->len, -+ &empty)) -+ return -1; -+ -+ idx++; -+ } -+ } -+ -+ if (elf_rebuild_rela_section(ip_relasec)) -+ return -1; -+ -+ return 0; -+} -diff --git a/tools/objtool/special.c b/tools/objtool/special.c -index bff8abb..84f001d 100644 ---- a/tools/objtool/special.c -+++ b/tools/objtool/special.c -@@ -91,16 +91,16 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, - alt->jump_or_nop = entry->jump_or_nop; - - if (alt->group) { -- alt->orig_len = *(unsigned char *)(sec->data + offset + -+ alt->orig_len = *(unsigned char *)(sec->data->d_buf + offset + - entry->orig_len); -- alt->new_len = *(unsigned char *)(sec->data + offset + -+ alt->new_len = *(unsigned char *)(sec->data->d_buf + offset + - entry->new_len); - } - - if (entry->feature) { - unsigned short feature; - -- feature = *(unsigned short *)(sec->data + offset + -+ feature = *(unsigned short *)(sec->data->d_buf + offset + - entry->feature); - - /* -diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh -new file mode 100755 -index 0000000..1470e74 ---- /dev/null -+++ b/tools/objtool/sync-check.sh -@@ -0,0 +1,29 @@ -+#!/bin/sh -+# SPDX-License-Identifier: GPL-2.0 -+ -+FILES=' -+arch/x86/lib/insn.c -+arch/x86/lib/inat.c -+arch/x86/lib/x86-opcode-map.txt -+arch/x86/tools/gen-insn-attr-x86.awk -+arch/x86/include/asm/insn.h -+arch/x86/include/asm/inat.h -+arch/x86/include/asm/inat_types.h -+arch/x86/include/asm/orc_types.h -+' -+ -+check() -+{ -+ local file=$1 -+ -+ diff $file ../../$file > /dev/null || -+ echo "Warning: synced file at 'tools/objtool/$file' differs from latest kernel version at '$file'" -+} -+ -+if [ ! -d ../../kernel ] || [ ! -d ../../tools ] || [ ! -d ../objtool ]; then -+ exit 0 -+fi -+ -+for i in $FILES; do -+ check $i -+done -diff --git a/tools/objtool/warn.h b/tools/objtool/warn.h -index ac7e075..afd9f7a 100644 ---- a/tools/objtool/warn.h -+++ b/tools/objtool/warn.h -@@ -18,6 +18,13 @@ - #ifndef _WARN_H - #define _WARN_H - -+#include <stdlib.h> -+#include <string.h> -+#include <sys/types.h> -+#include <sys/stat.h> -+#include <fcntl.h> -+#include "elf.h" -+ - extern const char *objname; - - static inline char *offstr(struct section *sec, unsigned long offset) -@@ -57,4 +64,7 @@ static inline char *offstr(struct section *sec, unsigned long offset) - free(_str); \ - }) - -+#define WARN_ELF(format, ...) \ -+ WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) -+ - #endif /* _WARN_H */ --- -2.7.4 - |