aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/linux-yocto-4.9.21/0088-objtool-sync-up-with-the-4.14.47-version-of-objtool.patch
diff options
context:
space:
mode:
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.patch9906
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, &sections_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
-