]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
move the 4.9 objtool patches to their own directory as this is going to be a separate...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 3 Jun 2018 12:02:52 +0000 (14:02 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 3 Jun 2018 12:02:52 +0000 (14:02 +0200)
31 files changed:
objtool-4.9/objdiff.patch [new file with mode: 0644]
objtool-4.9/objtool-detect-rip-relative-switch-table-references-part-2.patch [new file with mode: 0644]
objtool-4.9/objtool-detect-rip-relative-switch-table-references.patch [new file with mode: 0644]
objtool-4.9/objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch [new file with mode: 0644]
objtool-4.9/objtool-improve-detection-of-bug-and-other-dead-ends.patch [moved from queue-4.9/objtool-improve-detection-of-bug-and-other-dead-ends.patch with 100% similarity]
objtool-4.9/objtool-move-checking-code-to-check.c.patch [moved from queue-4.9/objtool-move-checking-code-to-check.c.patch with 100% similarity]
objtool-4.9/objtool-support-gcc-8-s-cold-subfunctions.patch [new file with mode: 0644]
objtool-4.9/objtool-support-gcc-8-switch-tables.patch [new file with mode: 0644]
objtool-4.9/objtool-x86-add-several-functions-and-files-to-the-objtool-whitelist.patch [new file with mode: 0644]
objtool-4.9/objtool_headers_sync.patch [new file with mode: 0644]
objtool-4.9/perf-tools-force-fixdep-compilation-at-the-start-of-the-build.patch [new file with mode: 0644]
objtool-4.9/perf-tools-move-headers-check-into-bash-script.patch [new file with mode: 0644]
objtool-4.9/perf_headers_sync.patch [new file with mode: 0644]
objtool-4.9/radix-tree-test-suite-remove-types.h.patch [new file with mode: 0644]
objtool-4.9/series [new file with mode: 0644]
objtool-4.9/tools-add-more-bitmap-functions.patch [new file with mode: 0644]
objtool-4.9/tools-enable-endian-checks-for-all-sparse-builds.patch [new file with mode: 0644]
objtool-4.9/tools-include-add-uint_max-def-to-kernel.h.patch [new file with mode: 0644]
objtool-4.9/tools-include-adopt-__compiletime_error.patch [new file with mode: 0644]
objtool-4.9/tools-include-adopt-__same_type-and-__must_be_array-from-the-kernel.patch [new file with mode: 0644]
objtool-4.9/tools-include-adopt-kernel-s-refcount.h.patch [new file with mode: 0644]
objtool-4.9/tools-include-drop-array_size-definition-from-linux-hashtable.h.patch [new file with mode: 0644]
objtool-4.9/tools-include-include-missing-headers-for-fls-and-types-in-linux-log2.h.patch [new file with mode: 0644]
objtool-4.9/tools-include-introduce-atomic_cmpxchg_-relaxed-release.patch [new file with mode: 0644]
objtool-4.9/tools-include-introduce-linux-bug.h-from-the-kernel-sources.patch [new file with mode: 0644]
objtool-4.9/tools-include-introduce-linux-compiler-gcc.h.patch [new file with mode: 0644]
objtool-4.9/tools-include-move-array_size-to-linux-kernel.h.patch [new file with mode: 0644]
objtool-4.9/tools-include-uapi-grab-copies-of-stat.h-and-fcntl.h.patch [new file with mode: 0644]
objtool-4.9/tools-lib-add-for_each_clear_bit-macro.patch [new file with mode: 0644]
objtool-4.9/xen-fixup.patch [new file with mode: 0644]
queue-4.9/series

diff --git a/objtool-4.9/objdiff.patch b/objtool-4.9/objdiff.patch
new file mode 100644 (file)
index 0000000..b070fdb
--- /dev/null
@@ -0,0 +1,9749 @@
+From foo@baz Sun Jun  3 12:35:15 CEST 2018
+Date: Sun, 03 Jun 2018 12:35:15 +0200
+To: Greg KH <gregkh@linuxfoundation.org>
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Subject: objtool: sync up with the 4.14.47 version of objtool
+
+
+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   |  201 +--
+ 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                              | 1297 +++++++++++++++++----
+ 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, 5498 insertions(+), 3125 deletions(-)
+
+--- /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 */
+--- /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 */
+--- 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
+--- 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 v
+ 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 i
+ 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
+        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
++b) ORC (Oops Rewind Capability) unwind table generation
+-   (NOTE: This is not yet implemented)
++   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.
+-   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.
+-
+-   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.
+-
+-   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 enfor
+    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.
+-2. asm_file.o: warning: objtool: .text+0x53: return instruction outside of a callable function
++   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.
++
++   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.
+-
+-   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.
++   Otherwise the stack frame may not get created before the call.
+-3. asm_file.o: warning: objtool: func()+0x9: function has unreachable instruction
++2. file.o: warning: objtool: .text+0x53: unreachable 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.
++   Objtool couldn't find a code path to reach the instruction.
+-   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 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 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 fi
+    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.
+--- 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.
+ $(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:
+--- 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 */
+--- 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
+--- 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 *
+       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 0x5d:
+-              if (!insn.rex_prefix.nbytes)
+-                      /* pop rbp */
+-                      *type = INSN_FP_RESTORE;
++      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 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 *
+               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 *
+       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;
++}
+--- /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
+--- /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
+--- /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 */
+--- /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 */
+--- 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 "};"
+-}
+-
+--- 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];
+-}
+-
+--- 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
+--- 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
+--- 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);
+-}
+--- 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 */
+--- 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: TEST Eb,Ib
+-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
+--- /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];
++}
++
+--- /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);
++}
+--- /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: TEST Eb,Ib
++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
+--- /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 "};"
++}
++
+--- 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 **arg
+       objname = argv[0];
+-      return check(objname, nofp);
++      return check(objname, false);
+ }
+--- /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;
++}
+--- 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 */
+--- /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 */
+--- 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_sam
+ {
+       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_
+ #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_
+ 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_f
+                               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 ob
+               "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 objt
+       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 ob
+       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 ob
+       }
+       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_
+       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_
+               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_f
+       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_f
+                               continue;
+                       func_for_each_insn(file, func, insn)
+-                              insn->visited = true;
++                              insn->ignore = true;
+               }
+       }
+ }
+@@ -415,8 +476,7 @@ static int add_jump_destinations(struct
+                   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
+                        * 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
+                       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 objto
+                           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 objto
+               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 objto
+               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 objto
+                       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 objto
+               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(stru
+               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(stru
+                       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 objto
+  *    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(st
+                                               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(st
+               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
+       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
+       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 objtoo
+       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 objtoo
+       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,21 +1203,522 @@ static bool is_fentry_call(struct instru
+       return false;
+ }
+-static bool has_modified_stack_frame(struct instruction *insn)
++static bool has_modified_stack_frame(struct insn_state *state)
+ {
+-      return (insn->state & STATE_FP_SAVED) ||
+-             (insn->state & STATE_FP_SETUP);
++      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 instruction *insn)
++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)
++{
++      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 void save_reg(struct insn_state *state, unsigned char reg, int base,
++                   int offset)
++{
++      if (arch_callee_saved_reg(reg) &&
++          state->regs[reg].base == CFI_UNDEFINED) {
++              state->regs[reg].base = base;
++              state->regs[reg].offset = offset;
++      }
++}
++
++static void restore_reg(struct insn_state *state, unsigned char reg)
++{
++      state->regs[reg].base = CFI_UNDEFINED;
++      state->regs[reg].offset = 0;
++}
++
++/*
++ * 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 update_insn_state(struct instruction *insn, struct insn_state *state)
+ {
+-      return (insn->state & STATE_FP_SAVED) &&
+-             (insn->state & STATE_FP_SETUP);
++      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;
++      }
++
++      if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET)
++              return update_insn_state_regs(insn, state);
++
++      switch (op->dest.type) {
++
++      case OP_DEST_REG:
++              switch (op->src.type) {
++
++              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) {
++
++                              /* mov %rsp, %rbp */
++                              cfa->base = op->dest.reg;
++                              state->bp_scratch = false;
++                      }
++
++                      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;
++              }
++
++              break;
++
++      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 unsigned int frame_state(unsigned long state)
++static bool insn_state_match(struct instruction *insn, struct insn_state *state)
+ {
+-      return (state & (STATE_FP_SAVED | STATE_FP_SETUP));
++      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;
+ }
+ /*
+@@ -980,19 +1727,17 @@ static unsigned int frame_state(unsigned
+  * 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, unsigned char first_state)
++static int validate_branch(struct objtool_file *file, struct instruction *first,
++                         struct insn_state state)
+ {
+       struct alternative *alt;
+-      struct instruction *insn;
++      struct instruction *insn, *next_insn;
+       struct section *sec;
+       struct symbol *func = NULL;
+-      unsigned char state;
+       int ret;
+       insn = first;
+       sec = insn->sec;
+-      state = first_state;
+       if (insn->alt_group && list_empty(&insn->alts)) {
+               WARN_FUNC("don't know how to handle branch to middle of alternative instruction group",
+@@ -1001,81 +1746,104 @@ static int validate_branch(struct objtoo
+       }
+       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;
+-                      }
++              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 (frame_state(insn->state) != frame_state(state)) {
+-                              WARN_FUNC("frame pointer state mismatch",
+-                                        sec, insn->offset);
++                      if (!insn->hint && !insn_state_match(insn, &state))
+                               return 1;
+-                      }
+                       return 0;
+               }
+-              insn->visited = true;
+-              insn->state = state;
+-
+-              list_for_each_entry(alt, &insn->alts, list) {
+-                      ret = validate_branch(file, alt->insn, state);
+-                      if (ret)
+-                              return 1;
+-              }
+-
+-              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;
+-                              state &= ~STATE_FP_SAVED;
++              insn->visited = true;
++
++              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 objtoo
+                       /* 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 objtoo
+               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 objtoo
+                       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 objtoo
+               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 instruc
+                       "__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(stru
+        *
+        * 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 obj
+       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
+       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);
+--- 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 */
+--- 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;
+@@ -140,12 +133,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;
+       }
+@@ -166,37 +159,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 */
+@@ -233,15 +226,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;
+               }
+@@ -323,8 +316,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;
+                       }
+@@ -348,9 +341,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);
+@@ -363,27 +357,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;
+       }
+@@ -403,12 +398,212 @@ err:
+       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);
+@@ -423,11 +618,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);
+ }
+--- 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,7 +83,7 @@ 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 symbol *find_symbol_containing(struct section *sec, unsigned long offset);
+@@ -84,8 +91,14 @@ struct rela *find_rela_by_dest(struct se
+ 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 */
+--- 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, co
+                       break;
+               } else {
+                       fprintf(stderr, "Unknown option: %s\n", cmd);
+-                      fprintf(stderr, "\n Usage: %s\n",
+-                              objtool_usage_string);
+-                      exit(1);
++                      cmd_usage();
+               }
+               (*argv)++;
+--- /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 */
+--- /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;
++}
+--- /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;
++}
+--- a/tools/objtool/special.c
++++ b/tools/objtool/special.c
+@@ -91,16 +91,16 @@ static int get_alt_entry(struct elf *elf
+       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);
+               /*
+--- /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
+--- 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 sectio
+       free(_str);                                     \
+ })
++#define WARN_ELF(format, ...)                         \
++      WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1))
++
+ #endif /* _WARN_H */
diff --git a/objtool-4.9/objtool-detect-rip-relative-switch-table-references-part-2.patch b/objtool-4.9/objtool-detect-rip-relative-switch-table-references-part-2.patch
new file mode 100644 (file)
index 0000000..199b116
--- /dev/null
@@ -0,0 +1,120 @@
+From 7dec80ccbe310fb7e225bf21c48c672bb780ce7b Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Fri, 18 May 2018 15:10:34 -0500
+Subject: objtool: Detect RIP-relative switch table references, part 2
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 7dec80ccbe310fb7e225bf21c48c672bb780ce7b upstream.
+
+With the following commit:
+
+  fd35c88b7417 ("objtool: Support GCC 8 switch tables")
+
+I added a "can't find switch jump table" warning, to stop covering up
+silent failures if add_switch_table() can't find anything.
+
+That warning found yet another bug in the objtool switch table detection
+logic.  For cases 1 and 2 (as described in the comments of
+find_switch_table()), the find_symbol_containing() check doesn't adjust
+the offset for RIP-relative switch jumps.
+
+Incidentally, this bug was already fixed for case 3 with:
+
+  6f5ec2993b1f ("objtool: Detect RIP-relative switch table references")
+
+However, that commit missed the fix for cases 1 and 2.
+
+The different cases are now starting to look more and more alike.  So
+fix the bug by consolidating them into a single case, by checking the
+original dynamic jump instruction in the case 3 loop.
+
+This also simplifies the code and makes it more robust against future
+switch table detection issues -- of which I'm sure there will be many...
+
+Switch table detection has been the most fragile area of objtool, by
+far.  I long for the day when we'll have a GCC plugin for annotating
+switch tables.  Linus asked me to delay such a plugin due to the
+flakiness of the plugin infrastructure in older versions of GCC, so this
+rickety code is what we're stuck with for now.  At least the code is now
+a little simpler than it was.
+
+Reported-by: kbuild test robot <lkp@intel.com>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/f400541613d45689086329432f3095119ffbc328.1526674218.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   37 ++++++++++++-------------------------
+ 1 file changed, 12 insertions(+), 25 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -900,40 +900,19 @@ static struct rela *find_switch_table(st
+       struct instruction *orig_insn = insn;
+       unsigned long table_offset;
+-      /* case 1 & 2 */
+-      text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
+-      if (text_rela && text_rela->sym == file->rodata->sym &&
+-          !find_symbol_containing(file->rodata, text_rela->addend)) {
+-
+-              table_offset = text_rela->addend;
+-              if (text_rela->type == R_X86_64_PC32) {
+-                      /* case 2 */
+-                      table_offset += 4;
+-                      file->ignore_unreachables = true;
+-              }
+-
+-              rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+-              if (!rodata_rela)
+-                      return NULL;
+-
+-              return rodata_rela;
+-      }
+-
+-      /* case 3 */
+       /*
+        * 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);
+-
++      for (;
+            &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)
++              if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
+                       break;
+               /* allow small jumps within the range */
+@@ -960,10 +939,18 @@ static struct rela *find_switch_table(st
+               if (find_symbol_containing(file->rodata, table_offset))
+                       continue;
+-              /* mov [rodata addr], %reg */
+               rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+-              if (rodata_rela)
++              if (rodata_rela) {
++                      /*
++                       * Use of RIP-relative switch jumps is quite rare, and
++                       * indicates a rare GCC quirk/bug which can leave dead
++                       * code behind.
++                       */
++                      if (text_rela->type == R_X86_64_PC32)
++                              file->ignore_unreachables = true;
++
+                       return rodata_rela;
++              }
+       }
+       return NULL;
diff --git a/objtool-4.9/objtool-detect-rip-relative-switch-table-references.patch b/objtool-4.9/objtool-detect-rip-relative-switch-table-references.patch
new file mode 100644 (file)
index 0000000..29d5604
--- /dev/null
@@ -0,0 +1,115 @@
+From 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Mon, 14 May 2018 08:53:24 -0500
+Subject: objtool: Detect RIP-relative switch table references
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 upstream.
+
+Typically a switch table can be found by detecting a .rodata access
+followed an indirect jump:
+
+    1969:      4a 8b 0c e5 00 00 00    mov    0x0(,%r12,8),%rcx
+    1970:      00
+                       196d: R_X86_64_32S      .rodata+0x438
+    1971:      e9 00 00 00 00          jmpq   1976 <dispc_runtime_suspend+0xb6a>
+                       1972: R_X86_64_PC32     __x86_indirect_thunk_rcx-0x4
+
+Randy Dunlap reported a case (seen with GCC 4.8) where the .rodata
+access uses RIP-relative addressing:
+
+    19bd:      48 8b 3d 00 00 00 00    mov    0x0(%rip),%rdi        # 19c4 <dispc_runtime_suspend+0xbb8>
+                       19c0: R_X86_64_PC32     .rodata+0x45c
+    19c4:      e9 00 00 00 00          jmpq   19c9 <dispc_runtime_suspend+0xbbd>
+                       19c5: R_X86_64_PC32     __x86_indirect_thunk_rdi-0x4
+
+In this case the relocation addend needs to be adjusted accordingly in
+order to find the location of the switch table.
+
+The fix is for case 3 (as described in the comments), but also make the
+existing case 1 & 2 checks more precise by only adjusting the addend for
+R_X86_64_PC32 relocations.
+
+This fixes the following warnings:
+
+  drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_suspend()+0xbb8: sibling call from callable instruction with modified stack frame
+  drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_resume()+0xcc5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/b6098294fd67afb69af8c47c9883d7a68bf0f8ea.1526305958.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   33 ++++++++++++++++++---------------
+ 1 file changed, 18 insertions(+), 15 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -898,24 +898,24 @@ static struct rela *find_switch_table(st
+ {
+       struct rela *text_rela, *rodata_rela;
+       struct instruction *orig_insn = insn;
++      unsigned long table_offset;
++      /* case 1 & 2 */
+       text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
+       if (text_rela && text_rela->sym == file->rodata->sym &&
+           !find_symbol_containing(file->rodata, text_rela->addend)) {
+-              /* case 1 */
+-              rodata_rela = find_rela_by_dest(file->rodata,
+-                                              text_rela->addend);
+-              if (rodata_rela)
+-                      return rodata_rela;
++              table_offset = text_rela->addend;
++              if (text_rela->type == R_X86_64_PC32) {
++                      /* case 2 */
++                      table_offset += 4;
++                      file->ignore_unreachables = true;
++              }
+-              /* case 2 */
+-              rodata_rela = find_rela_by_dest(file->rodata,
+-                                              text_rela->addend + 4);
++              rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+               if (!rodata_rela)
+                       return NULL;
+-              file->ignore_unreachables = true;
+               return rodata_rela;
+       }
+@@ -949,18 +949,21 @@ static struct rela *find_switch_table(st
+               if (!text_rela || text_rela->sym != file->rodata->sym)
+                       continue;
++              table_offset = text_rela->addend;
++              if (text_rela->type == R_X86_64_PC32)
++                      table_offset += 4;
++
+               /*
+                * Make sure the .rodata address isn't associated with a
+                * symbol.  gcc jump tables are anonymous data.
+                */
+-              if (find_symbol_containing(file->rodata, text_rela->addend))
++              if (find_symbol_containing(file->rodata, table_offset))
+                       continue;
+-              rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend);
+-              if (!rodata_rela)
+-                      continue;
+-
+-              return rodata_rela;
++              /* mov [rodata addr], %reg */
++              rodata_rela = find_rela_by_dest(file->rodata, table_offset);
++              if (rodata_rela)
++                      return rodata_rela;
+       }
+       return NULL;
diff --git a/objtool-4.9/objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch b/objtool-4.9/objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch
new file mode 100644 (file)
index 0000000..9ad4240
--- /dev/null
@@ -0,0 +1,60 @@
+From 0afd0d9e0e7879d666c1df2fa1bea4d8716909fe Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Wed, 9 May 2018 22:39:14 -0500
+Subject: objtool: Fix "noreturn" detection for recursive sibling calls
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 0afd0d9e0e7879d666c1df2fa1bea4d8716909fe upstream.
+
+Objtool has some crude logic for detecting static "noreturn" functions
+(aka "dead ends").  This is necessary for being able to correctly follow
+GCC code flow when such functions are called.
+
+It's remotely possible for two functions to call each other via sibling
+calls.  If they don't have RET instructions, objtool's noreturn
+detection logic goes into a recursive loop:
+
+  drivers/char/ipmi/ipmi_ssif.o: warning: objtool: return_hosed_msg()+0x0: infinite recursion (objtool bug!)
+  drivers/char/ipmi/ipmi_ssif.o: warning: objtool: deliver_recv_msg()+0x0: infinite recursion (objtool bug!)
+
+Instead of reporting an error in this case, consider the functions to be
+non-dead-ends.
+
+Reported-and-tested-by: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: damian <damian.tometzki@icloud.com>
+Link: http://lkml.kernel.org/r/7cc156408c5781a1f62085d352ced1fe39fe2f91.1525923412.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -207,9 +207,13 @@ static int __dead_end_function(struct ob
+                               /* local sibling call */
+                               if (recursion == 5) {
+-                                      WARN_FUNC("infinite recursion (objtool bug!)",
+-                                                dest->sec, dest->offset);
+-                                      return -1;
++                                      /*
++                                       * Infinite recursion: two functions
++                                       * have sibling calls to each other.
++                                       * This is a very rare case.  It means
++                                       * they aren't dead ends.
++                                       */
++                                      return 0;
+                               }
+                               return __dead_end_function(file, dest->func,
diff --git a/objtool-4.9/objtool-support-gcc-8-s-cold-subfunctions.patch b/objtool-4.9/objtool-support-gcc-8-s-cold-subfunctions.patch
new file mode 100644 (file)
index 0000000..dc1633c
--- /dev/null
@@ -0,0 +1,334 @@
+From 13810435b9a7014fb92eb715f77da488f3b65b99 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Wed, 9 May 2018 22:39:15 -0500
+Subject: objtool: Support GCC 8's cold subfunctions
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 13810435b9a7014fb92eb715f77da488f3b65b99 upstream.
+
+GCC 8 moves a lot of unlikely code out of line to "cold" subfunctions in
+.text.unlikely.  Properly detect the new subfunctions and treat them as
+extensions of the original functions.
+
+This fixes a bunch of warnings like:
+
+  kernel/cgroup/cgroup.o: warning: objtool: parse_cgroup_root_flags()+0x33: sibling call from callable instruction with modified stack frame
+  kernel/cgroup/cgroup.o: warning: objtool: cgroup_addrm_files()+0x290: sibling call from callable instruction with modified stack frame
+  kernel/cgroup/cgroup.o: warning: objtool: cgroup_apply_control_enable()+0x25b: sibling call from callable instruction with modified stack frame
+  kernel/cgroup/cgroup.o: warning: objtool: rebind_subsystems()+0x325: sibling call from callable instruction with modified stack frame
+
+Reported-and-tested-by: damian <damian.tometzki@icloud.com>
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/0965e7fcfc5f31a276f0c7f298ff770c19b68706.1525923412.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   93 +++++++++++++++++++++++++++-----------------------
+ tools/objtool/elf.c   |   42 +++++++++++++++++++++-
+ tools/objtool/elf.h   |    2 +
+ 3 files changed, 93 insertions(+), 44 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -59,6 +59,31 @@ static struct instruction *next_insn_sam
+       return next;
+ }
++static struct instruction *next_insn_same_func(struct objtool_file *file,
++                                             struct instruction *insn)
++{
++      struct instruction *next = list_next_entry(insn, list);
++      struct symbol *func = insn->func;
++
++      if (!func)
++              return NULL;
++
++      if (&next->list != &file->insn_list && next->func == func)
++              return next;
++
++      /* Check if we're already in the subfunction: */
++      if (func == func->cfunc)
++              return NULL;
++
++      /* Move to the subfunction: */
++      return find_insn(file, func->cfunc->sec, func->cfunc->offset);
++}
++
++#define func_for_each_insn_all(file, func, insn)                      \
++      for (insn = find_insn(file, func->sec, func->offset);           \
++           insn;                                                      \
++           insn = next_insn_same_func(file, insn))
++
+ #define func_for_each_insn(file, func, insn)                          \
+       for (insn = find_insn(file, func->sec, func->offset);           \
+            insn && &insn->list != &file->insn_list &&                 \
+@@ -148,10 +173,14 @@ static int __dead_end_function(struct ob
+                       if (!strcmp(func->name, global_noreturns[i]))
+                               return 1;
+-      if (!func->sec)
++      if (!func->len)
++              return 0;
++
++      insn = find_insn(file, func->sec, func->offset);
++      if (!insn->func)
+               return 0;
+-      func_for_each_insn(file, func, insn) {
++      func_for_each_insn_all(file, func, insn) {
+               empty = false;
+               if (insn->type == INSN_RETURN)
+@@ -166,35 +195,24 @@ static int __dead_end_function(struct ob
+        * case, the function's dead-end status depends on whether the target
+        * of the sibling call returns.
+        */
+-      func_for_each_insn(file, func, insn) {
+-              if (insn->sec != func->sec ||
+-                  insn->offset >= func->offset + func->len)
+-                      break;
+-
++      func_for_each_insn_all(file, func, insn) {
+               if (insn->type == INSN_JUMP_UNCONDITIONAL) {
+                       struct instruction *dest = insn->jump_dest;
+-                      struct symbol *dest_func;
+                       if (!dest)
+                               /* sibling call to another file */
+                               return 0;
+-                      if (dest->sec != func->sec ||
+-                          dest->offset < func->offset ||
+-                          dest->offset >= func->offset + func->len) {
+-                              /* local sibling call */
+-                              dest_func = find_symbol_by_offset(dest->sec,
+-                                                                dest->offset);
+-                              if (!dest_func)
+-                                      continue;
++                      if (dest->func && dest->func->pfunc != insn->func->pfunc) {
++                              /* local sibling call */
+                               if (recursion == 5) {
+                                       WARN_FUNC("infinite recursion (objtool bug!)",
+                                                 dest->sec, dest->offset);
+                                       return -1;
+                               }
+-                              return __dead_end_function(file, dest_func,
++                              return __dead_end_function(file, dest->func,
+                                                          recursion + 1);
+                       }
+               }
+@@ -421,7 +439,7 @@ static void add_ignores(struct objtool_f
+                       if (!ignore_func(file, func))
+                               continue;
+-                      func_for_each_insn(file, func, insn)
++                      func_for_each_insn_all(file, func, insn)
+                               insn->ignore = true;
+               }
+       }
+@@ -781,9 +799,8 @@ out:
+       return ret;
+ }
+-static int add_switch_table(struct objtool_file *file, struct symbol *func,
+-                          struct instruction *insn, struct rela *table,
+-                          struct rela *next_table)
++static int add_switch_table(struct objtool_file *file, struct instruction *insn,
++                          struct rela *table, struct rela *next_table)
+ {
+       struct rela *rela = table;
+       struct instruction *alt_insn;
+@@ -793,18 +810,13 @@ static int add_switch_table(struct objto
+               if (rela == next_table)
+                       break;
+-              if (rela->sym->sec != insn->sec ||
+-                  rela->addend <= func->offset ||
+-                  rela->addend >= func->offset + func->len)
++              alt_insn = find_insn(file, rela->sym->sec, rela->addend);
++              if (!alt_insn)
+                       break;
+-              alt_insn = find_insn(file, insn->sec, rela->addend);
+-              if (!alt_insn) {
+-                      WARN("%s: can't find instruction at %s+0x%x",
+-                           file->rodata->rela->name, insn->sec->name,
+-                           rela->addend);
+-                      return -1;
+-              }
++              /* Make sure the jmp dest is in the function or subfunction: */
++              if (alt_insn->func->pfunc != insn->func->pfunc)
++                      break;
+               alt = malloc(sizeof(*alt));
+               if (!alt) {
+@@ -942,7 +954,7 @@ static int add_func_switch_tables(struct
+       struct rela *rela, *prev_rela = NULL;
+       int ret;
+-      func_for_each_insn(file, func, insn) {
++      func_for_each_insn_all(file, func, insn) {
+               if (!last)
+                       last = insn;
+@@ -973,8 +985,7 @@ static int add_func_switch_tables(struct
+                * the beginning of another switch table in the same function.
+                */
+               if (prev_jump) {
+-                      ret = add_switch_table(file, func, prev_jump, prev_rela,
+-                                             rela);
++                      ret = add_switch_table(file, prev_jump, prev_rela, rela);
+                       if (ret)
+                               return ret;
+               }
+@@ -984,7 +995,7 @@ static int add_func_switch_tables(struct
+       }
+       if (prev_jump) {
+-              ret = add_switch_table(file, func, prev_jump, prev_rela, NULL);
++              ret = add_switch_table(file, prev_jump, prev_rela, NULL);
+               if (ret)
+                       return ret;
+       }
+@@ -1748,15 +1759,13 @@ static int validate_branch(struct objtoo
+       while (1) {
+               next_insn = next_insn_same_sec(file, insn);
+-
+-              if (file->c_file && func && insn->func && func != insn->func) {
++              if (file->c_file && func && insn->func && func != insn->func->pfunc) {
+                       WARN("%s() falls through to next function %s()",
+                            func->name, insn->func->name);
+                       return 1;
+               }
+-              if (insn->func)
+-                      func = insn->func;
++              func = insn->func ? insn->func->pfunc : NULL;
+               if (func && insn->ignore) {
+                       WARN_FUNC("BUG: why am I validating an ignored function?",
+@@ -1777,7 +1786,7 @@ static int validate_branch(struct objtoo
+                               i = insn;
+                               save_insn = NULL;
+-                              func_for_each_insn_continue_reverse(file, func, i) {
++                              func_for_each_insn_continue_reverse(file, insn->func, i) {
+                                       if (i->save) {
+                                               save_insn = i;
+                                               break;
+@@ -1864,7 +1873,7 @@ static int validate_branch(struct objtoo
+               case INSN_JUMP_UNCONDITIONAL:
+                       if (insn->jump_dest &&
+                           (!func || !insn->jump_dest->func ||
+-                           func == insn->jump_dest->func)) {
++                           insn->jump_dest->func->pfunc == func)) {
+                               ret = validate_branch(file, insn->jump_dest,
+                                                     state);
+                               if (ret)
+@@ -2059,7 +2068,7 @@ static int validate_functions(struct obj
+       for_each_sec(file, sec) {
+               list_for_each_entry(func, &sec->symbol_list, list) {
+-                      if (func->type != STT_FUNC)
++                      if (func->type != STT_FUNC || func->pfunc != func)
+                               continue;
+                       insn = find_insn(file, sec, func->offset);
+--- a/tools/objtool/elf.c
++++ b/tools/objtool/elf.c
+@@ -79,6 +79,19 @@ struct symbol *find_symbol_by_offset(str
+       return NULL;
+ }
++struct symbol *find_symbol_by_name(struct elf *elf, const char *name)
++{
++      struct section *sec;
++      struct symbol *sym;
++
++      list_for_each_entry(sec, &elf->sections, list)
++              list_for_each_entry(sym, &sec->symbol_list, list)
++                      if (!strcmp(sym->name, name))
++                              return sym;
++
++      return NULL;
++}
++
+ struct symbol *find_symbol_containing(struct section *sec, unsigned long offset)
+ {
+       struct symbol *sym;
+@@ -203,10 +216,11 @@ static int read_sections(struct elf *elf
+ static int read_symbols(struct elf *elf)
+ {
+-      struct section *symtab;
+-      struct symbol *sym;
++      struct section *symtab, *sec;
++      struct symbol *sym, *pfunc;
+       struct list_head *entry, *tmp;
+       int symbols_nr, i;
++      char *coldstr;
+       symtab = find_section_by_name(elf, ".symtab");
+       if (!symtab) {
+@@ -281,6 +295,30 @@ static int read_symbols(struct elf *elf)
+               hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx);
+       }
++      /* Create parent/child links for any cold subfunctions */
++      list_for_each_entry(sec, &elf->sections, list) {
++              list_for_each_entry(sym, &sec->symbol_list, list) {
++                      if (sym->type != STT_FUNC)
++                              continue;
++                      sym->pfunc = sym->cfunc = sym;
++                      coldstr = strstr(sym->name, ".cold.");
++                      if (coldstr) {
++                              coldstr[0] = '\0';
++                              pfunc = find_symbol_by_name(elf, sym->name);
++                              coldstr[0] = '.';
++
++                              if (!pfunc) {
++                                      WARN("%s(): can't find parent function",
++                                           sym->name);
++                                      goto err;
++                              }
++
++                              sym->pfunc = pfunc;
++                              pfunc->cfunc = sym;
++                      }
++              }
++      }
++
+       return 0;
+ err:
+--- a/tools/objtool/elf.h
++++ b/tools/objtool/elf.h
+@@ -61,6 +61,7 @@ struct symbol {
+       unsigned char bind, type;
+       unsigned long offset;
+       unsigned int len;
++      struct symbol *pfunc, *cfunc;
+ };
+ struct rela {
+@@ -86,6 +87,7 @@ struct elf {
+ 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 symbol *find_symbol_by_name(struct elf *elf, const char *name);
+ struct symbol *find_symbol_containing(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,
diff --git a/objtool-4.9/objtool-support-gcc-8-switch-tables.patch b/objtool-4.9/objtool-support-gcc-8-switch-tables.patch
new file mode 100644 (file)
index 0000000..c4f9b7f
--- /dev/null
@@ -0,0 +1,115 @@
+From fd35c88b74170d9335530d9abf271d5d73eb5401 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Thu, 10 May 2018 17:48:49 -0500
+Subject: objtool: Support GCC 8 switch tables
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit fd35c88b74170d9335530d9abf271d5d73eb5401 upstream.
+
+With GCC 8, some issues were found with the objtool switch table
+detection.
+
+1) In the .rodata section, immediately after the switch table, there can
+   be another object which contains a pointer to the function which had
+   the switch statement.  In this case objtool wrongly considers the
+   function pointer to be part of the switch table.  Fix it by:
+
+   a) making sure there are no pointers to the beginning of the
+      function; and
+
+   b) making sure there are no gaps in the switch table.
+
+   Only the former was needed, the latter adds additional protection for
+   future optimizations.
+
+2) In find_switch_table(), case 1 and case 2 are missing the check to
+   ensure that the .rodata switch table data is anonymous, i.e. that it
+   isn't already associated with an ELF symbol.  Fix it by adding the
+   same find_symbol_containing() check which is used for case 3.
+
+This fixes the following warnings with GCC 8:
+
+  drivers/block/virtio_blk.o: warning: objtool: virtio_queue_rq()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+72
+  net/ipv6/icmp.o: warning: objtool: icmpv6_rcv()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+64
+  drivers/usb/core/quirks.o: warning: objtool: quirks_param_set()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+48
+  drivers/mtd/nand/raw/nand_hynix.o: warning: objtool: hynix_nand_decode_id()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+24
+  drivers/mtd/nand/raw/nand_samsung.o: warning: objtool: samsung_nand_decode_id()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+32
+  drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.o: warning: objtool: gk104_top_oneinit()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+64
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Reported-by: kbuild test robot <lkp@intel.com>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: damian <damian.tometzki@icloud.com>
+Link: http://lkml.kernel.org/r/20180510224849.xwi34d6tzheb5wgw@treble
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   24 ++++++++++++++++++++++--
+ 1 file changed, 22 insertions(+), 2 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -805,17 +805,28 @@ static int add_switch_table(struct objto
+       struct rela *rela = table;
+       struct instruction *alt_insn;
+       struct alternative *alt;
++      struct symbol *pfunc = insn->func->pfunc;
++      unsigned int prev_offset = 0;
+       list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
+               if (rela == next_table)
+                       break;
++              /* Make sure the switch table entries are consecutive: */
++              if (prev_offset && rela->offset != prev_offset + 8)
++                      break;
++
++              /* Detect function pointers from contiguous objects: */
++              if (rela->sym->sec == pfunc->sec &&
++                  rela->addend == pfunc->offset)
++                      break;
++
+               alt_insn = find_insn(file, rela->sym->sec, rela->addend);
+               if (!alt_insn)
+                       break;
+               /* Make sure the jmp dest is in the function or subfunction: */
+-              if (alt_insn->func->pfunc != insn->func->pfunc)
++              if (alt_insn->func->pfunc != pfunc)
+                       break;
+               alt = malloc(sizeof(*alt));
+@@ -826,6 +837,13 @@ static int add_switch_table(struct objto
+               alt->insn = alt_insn;
+               list_add_tail(&alt->list, &insn->alts);
++              prev_offset = rela->offset;
++      }
++
++      if (!prev_offset) {
++              WARN_FUNC("can't find switch jump table",
++                        insn->sec, insn->offset);
++              return -1;
+       }
+       return 0;
+@@ -882,7 +900,9 @@ static struct rela *find_switch_table(st
+       struct instruction *orig_insn = insn;
+       text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
+-      if (text_rela && text_rela->sym == file->rodata->sym) {
++      if (text_rela && text_rela->sym == file->rodata->sym &&
++          !find_symbol_containing(file->rodata, text_rela->addend)) {
++
+               /* case 1 */
+               rodata_rela = find_rela_by_dest(file->rodata,
+                                               text_rela->addend);
diff --git a/objtool-4.9/objtool-x86-add-several-functions-and-files-to-the-objtool-whitelist.patch b/objtool-4.9/objtool-x86-add-several-functions-and-files-to-the-objtool-whitelist.patch
new file mode 100644 (file)
index 0000000..5d3bc92
--- /dev/null
@@ -0,0 +1,285 @@
+From c207aee48037abca71c669cbec407b9891965c34 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Wed, 28 Jun 2017 10:11:06 -0500
+Subject: objtool, x86: Add several functions and files to the objtool whitelist
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit c207aee48037abca71c669cbec407b9891965c34 upstream.
+
+In preparation for an objtool rewrite which will have broader checks,
+whitelist functions and files which cause problems because they do
+unusual things with the stack.
+
+These whitelists serve as a TODO list for which functions and files
+don't yet have undwarf unwinder coverage.  Eventually most of the
+whitelists can be removed in favor of manual CFI hint annotations or
+objtool improvements.
+
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Cc: Andy Lutomirski <luto@kernel.org>
+Cc: Jiri Slaby <jslaby@suse.cz>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: live-patching@vger.kernel.org
+Link: http://lkml.kernel.org/r/7f934a5d707a574bda33ea282e9478e627fb1829.1498659915.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/crypto/Makefile           |    2 ++
+ arch/x86/crypto/sha1-mb/Makefile   |    2 ++
+ arch/x86/crypto/sha256-mb/Makefile |    2 ++
+ arch/x86/kernel/Makefile           |    1 +
+ arch/x86/kernel/acpi/Makefile      |    2 ++
+ arch/x86/kernel/kprobes/opt.c      |    9 ++++++++-
+ arch/x86/kernel/reboot.c           |    2 ++
+ arch/x86/kvm/svm.c                 |    2 ++
+ arch/x86/kvm/vmx.c                 |    3 +++
+ arch/x86/lib/msr-reg.S             |    8 ++++----
+ arch/x86/net/Makefile              |    2 ++
+ arch/x86/platform/efi/Makefile     |    1 +
+ arch/x86/power/Makefile            |    2 ++
+ arch/x86/xen/Makefile              |    3 +++
+ kernel/kexec_core.c                |    4 +++-
+ 15 files changed, 39 insertions(+), 6 deletions(-)
+
+--- a/arch/x86/crypto/Makefile
++++ b/arch/x86/crypto/Makefile
+@@ -2,6 +2,8 @@
+ # Arch-specific CryptoAPI modules.
+ #
++OBJECT_FILES_NON_STANDARD := y
++
+ avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no)
+ avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
+                               $(comma)4)$(comma)%ymm2,yes,no)
+--- a/arch/x86/crypto/sha1-mb/Makefile
++++ b/arch/x86/crypto/sha1-mb/Makefile
+@@ -2,6 +2,8 @@
+ # Arch-specific CryptoAPI modules.
+ #
++OBJECT_FILES_NON_STANDARD := y
++
+ avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
+                                 $(comma)4)$(comma)%ymm2,yes,no)
+ ifeq ($(avx2_supported),yes)
+--- a/arch/x86/crypto/sha256-mb/Makefile
++++ b/arch/x86/crypto/sha256-mb/Makefile
+@@ -2,6 +2,8 @@
+ # Arch-specific CryptoAPI modules.
+ #
++OBJECT_FILES_NON_STANDARD := y
++
+ avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
+                                 $(comma)4)$(comma)%ymm2,yes,no)
+ ifeq ($(avx2_supported),yes)
+--- a/arch/x86/kernel/Makefile
++++ b/arch/x86/kernel/Makefile
+@@ -29,6 +29,7 @@ OBJECT_FILES_NON_STANDARD_head_$(BITS).o
+ OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o   := y
+ OBJECT_FILES_NON_STANDARD_mcount_$(BITS).o            := y
+ OBJECT_FILES_NON_STANDARD_test_nx.o                   := y
++OBJECT_FILES_NON_STANDARD_paravirt_patch_$(BITS).o    := y
+ # If instrumentation of this dir is enabled, boot hangs during first second.
+ # Probably could be more selective here, but note that files related to irqs,
+--- a/arch/x86/kernel/acpi/Makefile
++++ b/arch/x86/kernel/acpi/Makefile
+@@ -1,3 +1,5 @@
++OBJECT_FILES_NON_STANDARD_wakeup_$(BITS).o := y
++
+ obj-$(CONFIG_ACPI)            += boot.o
+ obj-$(CONFIG_ACPI_SLEEP)      += sleep.o wakeup_$(BITS).o
+ obj-$(CONFIG_ACPI_APEI)               += apei.o
+--- a/arch/x86/kernel/kprobes/opt.c
++++ b/arch/x86/kernel/kprobes/opt.c
+@@ -28,6 +28,7 @@
+ #include <linux/kdebug.h>
+ #include <linux/kallsyms.h>
+ #include <linux/ftrace.h>
++#include <linux/frame.h>
+ #include <asm/text-patching.h>
+ #include <asm/cacheflush.h>
+@@ -91,6 +92,7 @@ static void synthesize_set_arg1(kprobe_o
+ }
+ asm (
++                      "optprobe_template_func:\n"
+                       ".global optprobe_template_entry\n"
+                       "optprobe_template_entry:\n"
+ #ifdef CONFIG_X86_64
+@@ -128,7 +130,12 @@ asm (
+                       "       popf\n"
+ #endif
+                       ".global optprobe_template_end\n"
+-                      "optprobe_template_end:\n");
++                      "optprobe_template_end:\n"
++                      ".type optprobe_template_func, @function\n"
++                      ".size optprobe_template_func, .-optprobe_template_func\n");
++
++void optprobe_template_func(void);
++STACK_FRAME_NON_STANDARD(optprobe_template_func);
+ #define TMPL_MOVE_IDX \
+       ((long)&optprobe_template_val - (long)&optprobe_template_entry)
+--- a/arch/x86/kernel/reboot.c
++++ b/arch/x86/kernel/reboot.c
+@@ -9,6 +9,7 @@
+ #include <linux/sched.h>
+ #include <linux/tboot.h>
+ #include <linux/delay.h>
++#include <linux/frame.h>
+ #include <acpi/reboot.h>
+ #include <asm/io.h>
+ #include <asm/apic.h>
+@@ -127,6 +128,7 @@ void __noreturn machine_real_restart(uns
+ #ifdef CONFIG_APM_MODULE
+ EXPORT_SYMBOL(machine_real_restart);
+ #endif
++STACK_FRAME_NON_STANDARD(machine_real_restart);
+ /*
+  * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
+--- a/arch/x86/kvm/svm.c
++++ b/arch/x86/kvm/svm.c
+@@ -36,6 +36,7 @@
+ #include <linux/slab.h>
+ #include <linux/amd-iommu.h>
+ #include <linux/hashtable.h>
++#include <linux/frame.h>
+ #include <asm/apic.h>
+ #include <asm/perf_event.h>
+@@ -5111,6 +5112,7 @@ static void svm_vcpu_run(struct kvm_vcpu
+       mark_all_clean(svm->vmcb);
+ }
++STACK_FRAME_NON_STANDARD(svm_vcpu_run);
+ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
+ {
+--- a/arch/x86/kvm/vmx.c
++++ b/arch/x86/kvm/vmx.c
+@@ -33,6 +33,7 @@
+ #include <linux/slab.h>
+ #include <linux/tboot.h>
+ #include <linux/hrtimer.h>
++#include <linux/frame.h>
+ #include <linux/nospec.h>
+ #include "kvm_cache_regs.h"
+ #include "x86.h"
+@@ -8698,6 +8699,7 @@ static void vmx_handle_external_intr(str
+                       );
+       }
+ }
++STACK_FRAME_NON_STANDARD(vmx_handle_external_intr);
+ static bool vmx_has_emulated_msr(int index)
+ {
+@@ -9138,6 +9140,7 @@ static void __noclone vmx_vcpu_run(struc
+       vmx_recover_nmi_blocking(vmx);
+       vmx_complete_interrupts(vmx);
+ }
++STACK_FRAME_NON_STANDARD(vmx_vcpu_run);
+ static void vmx_load_vmcs01(struct kvm_vcpu *vcpu)
+ {
+--- a/arch/x86/lib/msr-reg.S
++++ b/arch/x86/lib/msr-reg.S
+@@ -13,14 +13,14 @@
+ .macro op_safe_regs op
+ ENTRY(\op\()_safe_regs)
+       pushq %rbx
+-      pushq %rbp
++      pushq %r12
+       movq    %rdi, %r10      /* Save pointer */
+       xorl    %r11d, %r11d    /* Return value */
+       movl    (%rdi), %eax
+       movl    4(%rdi), %ecx
+       movl    8(%rdi), %edx
+       movl    12(%rdi), %ebx
+-      movl    20(%rdi), %ebp
++      movl    20(%rdi), %r12d
+       movl    24(%rdi), %esi
+       movl    28(%rdi), %edi
+ 1:    \op
+@@ -29,10 +29,10 @@ ENTRY(\op\()_safe_regs)
+       movl    %ecx, 4(%r10)
+       movl    %edx, 8(%r10)
+       movl    %ebx, 12(%r10)
+-      movl    %ebp, 20(%r10)
++      movl    %r12d, 20(%r10)
+       movl    %esi, 24(%r10)
+       movl    %edi, 28(%r10)
+-      popq %rbp
++      popq %r12
+       popq %rbx
+       ret
+ 3:
+--- a/arch/x86/net/Makefile
++++ b/arch/x86/net/Makefile
+@@ -1,4 +1,6 @@
+ #
+ # Arch-specific network modules
+ #
++OBJECT_FILES_NON_STANDARD_bpf_jit.o += y
++
+ obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o
+--- a/arch/x86/platform/efi/Makefile
++++ b/arch/x86/platform/efi/Makefile
+@@ -1,4 +1,5 @@
+ OBJECT_FILES_NON_STANDARD_efi_thunk_$(BITS).o := y
++OBJECT_FILES_NON_STANDARD_efi_stub_$(BITS).o := y
+ obj-$(CONFIG_EFI)             += quirks.o efi.o efi_$(BITS).o efi_stub_$(BITS).o
+ obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
+--- a/arch/x86/power/Makefile
++++ b/arch/x86/power/Makefile
+@@ -1,3 +1,5 @@
++OBJECT_FILES_NON_STANDARD_hibernate_asm_$(BITS).o := y
++
+ # __restore_processor_state() restores %gs after S3 resume and so should not
+ # itself be stack-protected
+ nostackp := $(call cc-option, -fno-stack-protector)
+--- a/arch/x86/xen/Makefile
++++ b/arch/x86/xen/Makefile
+@@ -1,3 +1,6 @@
++OBJECT_FILES_NON_STANDARD_xen-asm_$(BITS).o := y
++OBJECT_FILES_NON_STANDARD_xen-pvh.o := y
++
+ ifdef CONFIG_FUNCTION_TRACER
+ # Do not profile debug and lowlevel utilities
+ CFLAGS_REMOVE_spinlock.o = -pg
+--- a/kernel/kexec_core.c
++++ b/kernel/kexec_core.c
+@@ -38,6 +38,7 @@
+ #include <linux/syscore_ops.h>
+ #include <linux/compiler.h>
+ #include <linux/hugetlb.h>
++#include <linux/frame.h>
+ #include <asm/page.h>
+ #include <asm/sections.h>
+@@ -878,7 +879,7 @@ int kexec_load_disabled;
+  * only when panic_cpu holds the current CPU number; this is the only CPU
+  * which processes crash_kexec routines.
+  */
+-void __crash_kexec(struct pt_regs *regs)
++void __noclone __crash_kexec(struct pt_regs *regs)
+ {
+       /* Take the kexec_mutex here to prevent sys_kexec_load
+        * running on one cpu from replacing the crash kernel
+@@ -900,6 +901,7 @@ void __crash_kexec(struct pt_regs *regs)
+               mutex_unlock(&kexec_mutex);
+       }
+ }
++STACK_FRAME_NON_STANDARD(__crash_kexec);
+ void crash_kexec(struct pt_regs *regs)
+ {
diff --git a/objtool-4.9/objtool_headers_sync.patch b/objtool-4.9/objtool_headers_sync.patch
new file mode 100644 (file)
index 0000000..a661ecc
--- /dev/null
@@ -0,0 +1,99 @@
+From foo@baz Sun Jun  3 12:35:51 CEST 2018
+Date: Sun, 03 Jun 2018 12:35:51 +0200
+To: Greg KH <gregkh@linuxfoundation.org>
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Subject: objtool: header file sync-up
+
+
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/arch/x86/include/asm/inat.h          |   10 ----------
+ tools/objtool/arch/x86/include/asm/orc_types.h     |    2 +-
+ tools/objtool/arch/x86/lib/x86-opcode-map.txt      |   15 +++------------
+ tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk |    1 -
+ 4 files changed, 4 insertions(+), 24 deletions(-)
+
+--- a/tools/objtool/arch/x86/include/asm/inat.h
++++ b/tools/objtool/arch/x86/include/asm/inat.h
+@@ -97,16 +97,6 @@
+ #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);
+--- a/tools/objtool/arch/x86/include/asm/orc_types.h
++++ b/tools/objtool/arch/x86/include/asm/orc_types.h
+@@ -88,7 +88,7 @@ struct orc_entry {
+       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
+--- a/tools/objtool/arch/x86/lib/x86-opcode-map.txt
++++ b/tools/objtool/arch/x86/lib/x86-opcode-map.txt
+@@ -607,7 +607,7 @@ fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(
+ 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
++ff:
+ EndTable
+ Table: 3-byte opcode 1 (0x0f 0x38)
+@@ -717,7 +717,7 @@ AVXcode: 2
+ 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)
++81: INVPID Gy,Mdq (66)
+ 82: INVPCID Gy,Mdq (66)
+ 83: vpmultishiftqb Vx,Hx,Wx (66),(ev)
+ 88: vexpandps/d Vpd,Wpd (66),(ev)
+@@ -970,15 +970,6 @@ GrpTable: Grp9
+ 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
+@@ -1018,7 +1009,7 @@ GrpTable: Grp15
+ 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)
++4: XSAVE
+ 5: XRSTOR | lfence (11B)
+ 6: XSAVEOPT | clwb (66) | mfence (11B)
+ 7: clflush | clflushopt (66) | sfence (11B)
+--- a/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk
++++ b/tools/objtool/arch/x86/tools/gen-insn-attr-x86.awk
+@@ -1,5 +1,4 @@
+ #!/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>
+ #
diff --git a/objtool-4.9/perf-tools-force-fixdep-compilation-at-the-start-of-the-build.patch b/objtool-4.9/perf-tools-force-fixdep-compilation-at-the-start-of-the-build.patch
new file mode 100644 (file)
index 0000000..c123921
--- /dev/null
@@ -0,0 +1,240 @@
+From abb26210a39522a6645bce3f438ed9a26bedb11b Mon Sep 17 00:00:00 2001
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Tue, 6 Dec 2016 14:18:49 +0100
+Subject: perf tools: Force fixdep compilation at the start of the build
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit abb26210a39522a6645bce3f438ed9a26bedb11b upstream.
+
+The fixdep tool needs to be built before everything else, because it fixes
+every object dependency file.
+
+We handle this currently by making all objects to depend on fixdep, which is
+error prone and is easily forgotten when new object is added.
+
+Instead of this, this patch force fixdep tool to be built as the first target
+in the separate make session. This way we don't need to handle extra fixdep
+dependencies and we are certain there's no fixdep race with any parallel make
+job.
+
+Committer notes:
+
+Testing it:
+
+Before:
+
+  $ rm -rf /tmp/build/perf/ ; mkdir -p /tmp/build/perf ; make -k O=/tmp/build/perf -C tools/perf install-bin
+  make: Entering directory '/home/acme/git/linux/tools/perf'
+    BUILD:   Doing 'make -j4' parallel build
+
+  Auto-detecting system features:
+  ...                         dwarf: [ on  ]
+  ...            dwarf_getlocations: [ on  ]
+  ...                         glibc: [ on  ]
+  ...                          gtk2: [ on  ]
+  ...                      libaudit: [ on  ]
+  ...                        libbfd: [ on  ]
+  ...                        libelf: [ on  ]
+  ...                       libnuma: [ on  ]
+  ...        numa_num_possible_cpus: [ on  ]
+  ...                       libperl: [ on  ]
+  ...                     libpython: [ on  ]
+  ...                      libslang: [ on  ]
+  ...                     libcrypto: [ on  ]
+  ...                     libunwind: [ on  ]
+  ...            libdw-dwarf-unwind: [ on  ]
+  ...                          zlib: [ on  ]
+  ...                          lzma: [ on  ]
+  ...                     get_cpuid: [ on  ]
+  ...                           bpf: [ on  ]
+
+    GEN      /tmp/build/perf/common-cmds.h
+    HOSTCC   /tmp/build/perf/fixdep.o
+    HOSTLD   /tmp/build/perf/fixdep-in.o
+    LINK     /tmp/build/perf/fixdep
+    MKDIR    /tmp/build/perf/pmu-events/
+    HOSTCC   /tmp/build/perf/pmu-events/json.o
+    MKDIR    /tmp/build/perf/pmu-events/
+    HOSTCC   /tmp/build/perf/pmu-events/jsmn.o
+    HOSTCC   /tmp/build/perf/pmu-events/jevents.o
+    HOSTLD   /tmp/build/perf/pmu-events/jevents-in.o
+    PERF_VERSION = 4.9.rc8.g868cd5
+    CC       /tmp/build/perf/perf-read-vdso32
+  <SNIP>
+
+After:
+
+  $ rm -rf /tmp/build/perf/ ; mkdir -p /tmp/build/perf ; make -k O=/tmp/build/perf -C tools/perf install-bin
+  make: Entering directory '/home/acme/git/linux/tools/perf'
+    BUILD:   Doing 'make -j4' parallel build
+    HOSTCC   /tmp/build/perf/fixdep.o
+    HOSTLD   /tmp/build/perf/fixdep-in.o
+    LINK     /tmp/build/perf/fixdep
+
+  Auto-detecting system features:
+  ...                         dwarf: [ on  ]
+  ...            dwarf_getlocations: [ on  ]
+  ...                         glibc: [ on  ]
+  ...                          gtk2: [ on  ]
+  ...                      libaudit: [ on  ]
+  ...                        libbfd: [ on  ]
+  ...                        libelf: [ on  ]
+  ...                       libnuma: [ on  ]
+  ...        numa_num_possible_cpus: [ on  ]
+  ...                       libperl: [ on  ]
+  ...                     libpython: [ on  ]
+  ...                      libslang: [ on  ]
+  ...                     libcrypto: [ on  ]
+  ...                     libunwind: [ on  ]
+  ...            libdw-dwarf-unwind: [ on  ]
+  ...                          zlib: [ on  ]
+  ...                          lzma: [ on  ]
+  ...                     get_cpuid: [ on  ]
+  ...                           bpf: [ on  ]
+
+    GEN      /tmp/build/perf/common-cmds.h
+    MKDIR    /tmp/build/perf/fd/
+    CC       /tmp/build/perf/fd/array.o
+    LD       /tmp/build/perf/fd/libapi-in.o
+    MKDIR    /tmp/build/perf/fs/
+    CC       /tmp/build/perf/event-parse.o
+    CC       /tmp/build/perf/fs/fs.o
+    PERF_VERSION = 4.9.rc8.g57a92f
+    CC       /tmp/build/perf/event-plugin.o
+    MKDIR    /tmp/build/perf/fs/
+    CC       /tmp/build/perf/fs/tracing_path.o
+  <SNIP>
+
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Link: http://lkml.kernel.org/r/1481030331-31944-3-git-send-email-jolsa@kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/perf/Makefile.perf |   50 +++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 38 insertions(+), 12 deletions(-)
+
+--- a/tools/perf/Makefile.perf
++++ b/tools/perf/Makefile.perf
+@@ -177,6 +177,35 @@ ifeq ($(filter-out $(NON_CONFIG_TARGETS)
+ endif
+ endif
++# The fixdep build - we force fixdep tool to be built as
++# the first target in the separate make session not to be
++# disturbed by any parallel make jobs. Once fixdep is done
++# we issue the requested build with FIXDEP=1 variable.
++#
++# The fixdep build is disabled for $(NON_CONFIG_TARGETS)
++# targets, because it's not necessary.
++
++ifdef FIXDEP
++  force_fixdep := 0
++else
++  force_fixdep := $(config)
++endif
++
++export srctree OUTPUT RM CC CXX LD AR CFLAGS CXXFLAGS V BISON FLEX AWK
++export HOSTCC HOSTLD HOSTAR
++
++include $(srctree)/tools/build/Makefile.include
++
++ifeq ($(force_fixdep),1)
++goals := $(filter-out all sub-make, $(MAKECMDGOALS))
++
++$(goals) all: sub-make
++
++sub-make: fixdep
++      $(Q)$(MAKE) FIXDEP=1 -f Makefile.perf $(goals)
++
++else # force_fixdep
++
+ # Set FEATURE_TESTS to 'all' so all possible feature checkers are executed.
+ # Without this setting the output feature dump file misses some features, for
+ # example, liberty. Select all checkers so we won't get an incomplete feature
+@@ -348,10 +377,6 @@ strip: $(PROGRAMS) $(OUTPUT)perf
+ PERF_IN := $(OUTPUT)perf-in.o
+-export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK
+-export HOSTCC HOSTLD HOSTAR
+-include $(srctree)/tools/build/Makefile.include
+-
+ JEVENTS       := $(OUTPUT)pmu-events/jevents
+ JEVENTS_IN    := $(OUTPUT)pmu-events/jevents-in.o
+@@ -470,7 +495,7 @@ $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(
+       $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \
+               $(PERF_IN) $(PMU_EVENTS_IN) $(LIBS) -o $@
+-$(GTK_IN): fixdep FORCE
++$(GTK_IN): FORCE
+       $(Q)$(MAKE) $(build)=gtk
+ $(OUTPUT)libperf-gtk.so: $(GTK_IN) $(PERFLIBS)
+@@ -515,7 +540,7 @@ endif
+ __build-dir = $(subst $(OUTPUT),,$(dir $@))
+ build-dir   = $(if $(__build-dir),$(__build-dir),.)
+-prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep archheaders
++prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders
+ $(OUTPUT)%.o: %.c prepare FORCE
+       $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@
+@@ -555,7 +580,7 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(wi
+ LIBPERF_IN := $(OUTPUT)libperf-in.o
+-$(LIBPERF_IN): prepare fixdep FORCE
++$(LIBPERF_IN): prepare FORCE
+       $(Q)$(MAKE) $(build)=libperf
+ $(LIB_FILE): $(LIBPERF_IN)
+@@ -563,10 +588,10 @@ $(LIB_FILE): $(LIBPERF_IN)
+ LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ)
+-$(LIBTRACEEVENT): fixdep FORCE
++$(LIBTRACEEVENT): FORCE
+       $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a
+-libtraceevent_plugins: fixdep FORCE
++libtraceevent_plugins: FORCE
+       $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins
+ $(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins
+@@ -579,21 +604,21 @@ $(LIBTRACEEVENT)-clean:
+ install-traceevent-plugins: libtraceevent_plugins
+       $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins
+-$(LIBAPI): fixdep FORCE
++$(LIBAPI): FORCE
+       $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a
+ $(LIBAPI)-clean:
+       $(call QUIET_CLEAN, libapi)
+       $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
+-$(LIBBPF): fixdep FORCE
++$(LIBBPF): FORCE
+       $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT)
+ $(LIBBPF)-clean:
+       $(call QUIET_CLEAN, libbpf)
+       $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null
+-$(LIBSUBCMD): fixdep FORCE
++$(LIBSUBCMD): FORCE
+       $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a
+ $(LIBSUBCMD)-clean:
+@@ -790,3 +815,4 @@ FORCE:
+ .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare
+ .PHONY: libtraceevent_plugins archheaders
++endif # force_fixdep
diff --git a/objtool-4.9/perf-tools-move-headers-check-into-bash-script.patch b/objtool-4.9/perf-tools-move-headers-check-into-bash-script.patch
new file mode 100644 (file)
index 0000000..c2971fe
--- /dev/null
@@ -0,0 +1,203 @@
+From aeafd623f866c429307e3a4a39998f5f06b4f00e Mon Sep 17 00:00:00 2001
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Tue, 6 Dec 2016 14:18:51 +0100
+Subject: perf tools: Move headers check into bash script
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit aeafd623f866c429307e3a4a39998f5f06b4f00e upstream.
+
+To make it nicer and easily maintainable.
+
+Also moving the check into fixdep sub make, so its output is not
+scattered around the build output.
+
+Removing extra $$ from mman*.h checks.
+
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Link: http://lkml.kernel.org/r/1481030331-31944-5-git-send-email-jolsa@kernel.org
+[ Use /bin/sh, and 'function check() {' -> 'check () {' to make it work with busybox, in Alpine Linux, for instance ]
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/perf/Makefile.perf    |   94 --------------------------------------------
+ tools/perf/check-headers.sh |   59 +++++++++++++++++++++++++++
+ 2 files changed, 60 insertions(+), 93 deletions(-)
+
+--- a/tools/perf/Makefile.perf
++++ b/tools/perf/Makefile.perf
+@@ -202,6 +202,7 @@ goals := $(filter-out all sub-make, $(MA
+ $(goals) all: sub-make
+ sub-make: fixdep
++      @./check-headers.sh
+       $(Q)$(MAKE) FIXDEP=1 -f Makefile.perf $(goals)
+ else # force_fixdep
+@@ -387,99 +388,6 @@ export JEVENTS
+ build := -f $(srctree)/tools/build/Makefile.build dir=. obj
+ $(PERF_IN): prepare FORCE
+-      @(test -f ../../include/uapi/linux/perf_event.h && ( \
+-        (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \
+-        || echo "Warning: tools/include/uapi/linux/perf_event.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/linux/hash.h && ( \
+-        (diff -B ../include/linux/hash.h ../../include/linux/hash.h >/dev/null) \
+-        || echo "Warning: tools/include/linux/hash.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/uapi/linux/hw_breakpoint.h && ( \
+-        (diff -B ../include/uapi/linux/hw_breakpoint.h ../../include/uapi/linux/hw_breakpoint.h >/dev/null) \
+-        || echo "Warning: tools/include/uapi/linux/hw_breakpoint.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/include/asm/disabled-features.h && ( \
+-        (diff -B ../arch/x86/include/asm/disabled-features.h ../../arch/x86/include/asm/disabled-features.h >/dev/null) \
+-        || echo "Warning: tools/arch/x86/include/asm/disabled-features.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/include/asm/required-features.h && ( \
+-        (diff -B ../arch/x86/include/asm/required-features.h ../../arch/x86/include/asm/required-features.h >/dev/null) \
+-        || echo "Warning: tools/arch/x86/include/asm/required-features.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/include/asm/cpufeatures.h && ( \
+-        (diff -B ../arch/x86/include/asm/cpufeatures.h ../../arch/x86/include/asm/cpufeatures.h >/dev/null) \
+-        || echo "Warning: tools/arch/x86/include/asm/cpufeatures.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/lib/memcpy_64.S && ( \
+-        (diff -B ../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memcpy_64.S >/dev/null) \
+-        || echo "Warning: tools/arch/x86/lib/memcpy_64.S differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/lib/memset_64.S && ( \
+-        (diff -B ../arch/x86/lib/memset_64.S ../../arch/x86/lib/memset_64.S >/dev/null) \
+-        || echo "Warning: tools/arch/x86/lib/memset_64.S differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/arm/include/uapi/asm/perf_regs.h && ( \
+-        (diff -B ../arch/arm/include/uapi/asm/perf_regs.h ../../arch/arm/include/uapi/asm/perf_regs.h >/dev/null) \
+-        || echo "Warning: tools/arch/arm/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/arm64/include/uapi/asm/perf_regs.h && ( \
+-        (diff -B ../arch/arm64/include/uapi/asm/perf_regs.h ../../arch/arm64/include/uapi/asm/perf_regs.h >/dev/null) \
+-        || echo "Warning: tools/arch/arm64/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/powerpc/include/uapi/asm/perf_regs.h && ( \
+-        (diff -B ../arch/powerpc/include/uapi/asm/perf_regs.h ../../arch/powerpc/include/uapi/asm/perf_regs.h >/dev/null) \
+-        || echo "Warning: tools/arch/powerpc/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/include/uapi/asm/perf_regs.h && ( \
+-        (diff -B ../arch/x86/include/uapi/asm/perf_regs.h ../../arch/x86/include/uapi/asm/perf_regs.h >/dev/null) \
+-        || echo "Warning: tools/arch/x86/include/uapi/asm/perf_regs.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/include/uapi/asm/kvm.h && ( \
+-        (diff -B ../arch/x86/include/uapi/asm/kvm.h ../../arch/x86/include/uapi/asm/kvm.h >/dev/null) \
+-        || echo "Warning: tools/arch/x86/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/include/uapi/asm/kvm_perf.h && ( \
+-        (diff -B ../arch/x86/include/uapi/asm/kvm_perf.h ../../arch/x86/include/uapi/asm/kvm_perf.h >/dev/null) \
+-        || echo "Warning: tools/arch/x86/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/include/uapi/asm/svm.h && ( \
+-        (diff -B ../arch/x86/include/uapi/asm/svm.h ../../arch/x86/include/uapi/asm/svm.h >/dev/null) \
+-        || echo "Warning: tools/arch/x86/include/uapi/asm/svm.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/x86/include/uapi/asm/vmx.h && ( \
+-        (diff -B ../arch/x86/include/uapi/asm/vmx.h ../../arch/x86/include/uapi/asm/vmx.h >/dev/null) \
+-        || echo "Warning: tools/arch/x86/include/uapi/asm/vmx.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/powerpc/include/uapi/asm/kvm.h && ( \
+-        (diff -B ../arch/powerpc/include/uapi/asm/kvm.h ../../arch/powerpc/include/uapi/asm/kvm.h >/dev/null) \
+-        || echo "Warning: tools/arch/powerpc/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/s390/include/uapi/asm/kvm.h && ( \
+-        (diff -B ../arch/s390/include/uapi/asm/kvm.h ../../arch/s390/include/uapi/asm/kvm.h >/dev/null) \
+-        || echo "Warning: tools/arch/s390/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/s390/include/uapi/asm/kvm_perf.h && ( \
+-        (diff -B ../arch/s390/include/uapi/asm/kvm_perf.h ../../arch/s390/include/uapi/asm/kvm_perf.h >/dev/null) \
+-        || echo "Warning: tools/arch/s390/include/uapi/asm/kvm_perf.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/s390/include/uapi/asm/sie.h && ( \
+-        (diff -B ../arch/s390/include/uapi/asm/sie.h ../../arch/s390/include/uapi/asm/sie.h >/dev/null) \
+-        || echo "Warning: tools/arch/s390/include/uapi/asm/sie.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/arm/include/uapi/asm/kvm.h && ( \
+-        (diff -B ../arch/arm/include/uapi/asm/kvm.h ../../arch/arm/include/uapi/asm/kvm.h >/dev/null) \
+-        || echo "Warning: tools/arch/arm/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
+-      @(test -f ../../arch/arm64/include/uapi/asm/kvm.h && ( \
+-        (diff -B ../arch/arm64/include/uapi/asm/kvm.h ../../arch/arm64/include/uapi/asm/kvm.h >/dev/null) \
+-        || echo "Warning: tools/arch/arm64/include/uapi/asm/kvm.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/asm-generic/bitops/arch_hweight.h && ( \
+-        (diff -B ../include/asm-generic/bitops/arch_hweight.h ../../include/asm-generic/bitops/arch_hweight.h >/dev/null) \
+-        || echo "Warning: tools/include/asm-generic/bitops/arch_hweight.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/asm-generic/bitops/const_hweight.h && ( \
+-        (diff -B ../include/asm-generic/bitops/const_hweight.h ../../include/asm-generic/bitops/const_hweight.h >/dev/null) \
+-        || echo "Warning: tools/include/asm-generic/bitops/const_hweight.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/asm-generic/bitops/__fls.h && ( \
+-        (diff -B ../include/asm-generic/bitops/__fls.h ../../include/asm-generic/bitops/__fls.h >/dev/null) \
+-        || echo "Warning: tools/include/asm-generic/bitops/__fls.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/asm-generic/bitops/fls.h && ( \
+-        (diff -B ../include/asm-generic/bitops/fls.h ../../include/asm-generic/bitops/fls.h >/dev/null) \
+-        || echo "Warning: tools/include/asm-generic/bitops/fls.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/asm-generic/bitops/fls64.h && ( \
+-        (diff -B ../include/asm-generic/bitops/fls64.h ../../include/asm-generic/bitops/fls64.h >/dev/null) \
+-        || echo "Warning: tools/include/asm-generic/bitops/fls64.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/linux/coresight-pmu.h && ( \
+-      (diff -B ../include/linux/coresight-pmu.h ../../include/linux/coresight-pmu.h >/dev/null) \
+-      || echo "Warning: tools/include/linux/coresight-pmu.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/uapi/asm-generic/mman-common.h && ( \
+-      (diff -B ../include/uapi/asm-generic/mman-common.h ../../include/uapi/asm-generic/mman-common.h >/dev/null) \
+-      || echo "Warning: tools/include/uapi/asm-generic/mman-common.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/uapi/asm-generic/mman.h && ( \
+-      (diff -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>$$" ../include/uapi/asm-generic/mman.h ../../include/uapi/asm-generic/mman.h >/dev/null) \
+-      || echo "Warning: tools/include/uapi/asm-generic/mman.h differs from kernel" >&2 )) || true
+-      @(test -f ../../include/uapi/linux/mman.h && ( \
+-      (diff -B -I "^#include <\(uapi/\)*asm/mman.h>$$" ../include/uapi/linux/mman.h ../../include/uapi/linux/mman.h >/dev/null) \
+-      || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true
+       $(Q)$(MAKE) $(build)=perf
+ $(JEVENTS_IN): FORCE
+--- /dev/null
++++ b/tools/perf/check-headers.sh
+@@ -0,0 +1,59 @@
++#!/bin/sh
++
++HEADERS='
++include/uapi/linux/perf_event.h
++include/linux/hash.h
++include/uapi/linux/hw_breakpoint.h
++arch/x86/include/asm/disabled-features.h
++arch/x86/include/asm/required-features.h
++arch/x86/include/asm/cpufeatures.h
++arch/arm/include/uapi/asm/perf_regs.h
++arch/arm64/include/uapi/asm/perf_regs.h
++arch/powerpc/include/uapi/asm/perf_regs.h
++arch/x86/include/uapi/asm/perf_regs.h
++arch/x86/include/uapi/asm/kvm.h
++arch/x86/include/uapi/asm/kvm_perf.h
++arch/x86/include/uapi/asm/svm.h
++arch/x86/include/uapi/asm/vmx.h
++arch/powerpc/include/uapi/asm/kvm.h
++arch/s390/include/uapi/asm/kvm.h
++arch/s390/include/uapi/asm/kvm_perf.h
++arch/s390/include/uapi/asm/sie.h
++arch/arm/include/uapi/asm/kvm.h
++arch/arm64/include/uapi/asm/kvm.h
++include/asm-generic/bitops/arch_hweight.h
++include/asm-generic/bitops/const_hweight.h
++include/asm-generic/bitops/__fls.h
++include/asm-generic/bitops/fls.h
++include/asm-generic/bitops/fls64.h
++include/linux/coresight-pmu.h
++include/uapi/asm-generic/mman-common.h
++'
++
++check () {
++  file=$1
++  opts=
++
++  shift
++  while [ -n "$*" ]; do
++    opts="$opts \"$1\""
++    shift
++  done
++
++  cmd="diff $opts ../$file ../../$file > /dev/null"
++
++  test -f ../../$file &&
++  eval $cmd || echo "Warning: $file differs from kernel" >&2
++}
++
++
++# simple diff check
++for i in $HEADERS; do
++  check $i -B
++done
++
++# diff with extra ignore lines
++check arch/x86/lib/memcpy_64.S        -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"
++check arch/x86/lib/memset_64.S        -B -I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"
++check include/uapi/asm-generic/mman.h -B -I "^#include <\(uapi/\)*asm-generic/mman-common.h>"
++check include/uapi/linux/mman.h       -B -I "^#include <\(uapi/\)*asm/mman.h>"
diff --git a/objtool-4.9/perf_headers_sync.patch b/objtool-4.9/perf_headers_sync.patch
new file mode 100644 (file)
index 0000000..3311a5f
--- /dev/null
@@ -0,0 +1,496 @@
+From foo@baz Sun Jun  3 12:36:14 CEST 2018
+Date: Sun, 03 Jun 2018 12:36:14 +0200
+To: Greg KH <gregkh@linuxfoundation.org>
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Subject: perf/tools: header file sync up
+
+
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/arch/arm/include/uapi/asm/kvm.h             |   13 ++
+ tools/arch/arm64/include/uapi/asm/kvm.h           |    6 +
+ tools/arch/powerpc/include/uapi/asm/kvm.h         |    1 
+ tools/arch/s390/include/uapi/asm/kvm.h            |    5 
+ tools/arch/x86/include/asm/cpufeatures.h          |   44 ++++++-
+ tools/arch/x86/include/asm/disabled-features.h    |    7 -
+ tools/arch/x86/include/asm/required-features.h    |    3 
+ tools/include/uapi/asm-generic/mman-common.h      |    5 
+ tools/include/uapi/linux/bpf.h                    |   51 ++++++++
+ tools/include/uapi/linux/fcntl.h                  |    5 
+ tools/include/uapi/linux/stat.h                   |  131 ----------------------
+ tools/perf/arch/x86/entry/syscalls/syscall_64.tbl |    7 -
+ 12 files changed, 132 insertions(+), 146 deletions(-)
+
+--- a/tools/arch/arm/include/uapi/asm/kvm.h
++++ b/tools/arch/arm/include/uapi/asm/kvm.h
+@@ -84,6 +84,13 @@ struct kvm_regs {
+ #define KVM_VGIC_V2_DIST_SIZE         0x1000
+ #define KVM_VGIC_V2_CPU_SIZE          0x2000
++/* Supported VGICv3 address types  */
++#define KVM_VGIC_V3_ADDR_TYPE_DIST    2
++#define KVM_VGIC_V3_ADDR_TYPE_REDIST  3
++
++#define KVM_VGIC_V3_DIST_SIZE         SZ_64K
++#define KVM_VGIC_V3_REDIST_SIZE               (2 * SZ_64K)
++
+ #define KVM_ARM_VCPU_POWER_OFF                0 /* CPU is started in OFF state */
+ #define KVM_ARM_VCPU_PSCI_0_2         1 /* CPU uses PSCI v0.2 */
+@@ -166,6 +173,12 @@ struct kvm_arch_memory_slot {
+ #define KVM_REG_ARM_VFP_FPINST                0x1009
+ #define KVM_REG_ARM_VFP_FPINST2               0x100A
++/* KVM-as-firmware specific pseudo-registers */
++#define KVM_REG_ARM_FW                        (0x0014 << KVM_REG_ARM_COPROC_SHIFT)
++#define KVM_REG_ARM_FW_REG(r)         (KVM_REG_ARM | KVM_REG_SIZE_U64 | \
++                                       KVM_REG_ARM_FW | ((r) & 0xffff))
++#define KVM_REG_ARM_PSCI_VERSION      KVM_REG_ARM_FW_REG(0)
++
+ /* Device Control API: ARM VGIC */
+ #define KVM_DEV_ARM_VGIC_GRP_ADDR     0
+ #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS        1
+--- a/tools/arch/arm64/include/uapi/asm/kvm.h
++++ b/tools/arch/arm64/include/uapi/asm/kvm.h
+@@ -195,6 +195,12 @@ struct kvm_arch_memory_slot {
+ #define KVM_REG_ARM_TIMER_CNT         ARM64_SYS_REG(3, 3, 14, 3, 2)
+ #define KVM_REG_ARM_TIMER_CVAL                ARM64_SYS_REG(3, 3, 14, 0, 2)
++/* KVM-as-firmware specific pseudo-registers */
++#define KVM_REG_ARM_FW                        (0x0014 << KVM_REG_ARM_COPROC_SHIFT)
++#define KVM_REG_ARM_FW_REG(r)         (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \
++                                       KVM_REG_ARM_FW | ((r) & 0xffff))
++#define KVM_REG_ARM_PSCI_VERSION      KVM_REG_ARM_FW_REG(0)
++
+ /* Device Control API: ARM VGIC */
+ #define KVM_DEV_ARM_VGIC_GRP_ADDR     0
+ #define KVM_DEV_ARM_VGIC_GRP_DIST_REGS        1
+--- a/tools/arch/powerpc/include/uapi/asm/kvm.h
++++ b/tools/arch/powerpc/include/uapi/asm/kvm.h
+@@ -596,6 +596,7 @@ struct kvm_get_htab_header {
+ #define KVM_REG_PPC_TM_VSCR   (KVM_REG_PPC_TM | KVM_REG_SIZE_U32 | 0x67)
+ #define KVM_REG_PPC_TM_DSCR   (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x68)
+ #define KVM_REG_PPC_TM_TAR    (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x69)
++#define KVM_REG_PPC_TM_XER    (KVM_REG_PPC_TM | KVM_REG_SIZE_U64 | 0x6a)
+ /* PPC64 eXternal Interrupt Controller Specification */
+ #define KVM_DEV_XICS_GRP_SOURCES      1       /* 64-bit source attributes */
+--- a/tools/arch/s390/include/uapi/asm/kvm.h
++++ b/tools/arch/s390/include/uapi/asm/kvm.h
+@@ -197,6 +197,7 @@ struct kvm_guest_debug_arch {
+ #define KVM_SYNC_VRS    (1UL << 6)
+ #define KVM_SYNC_RICCB  (1UL << 7)
+ #define KVM_SYNC_FPRS   (1UL << 8)
++#define KVM_SYNC_BPBC (1UL << 10)
+ /* definition of registers in kvm_run */
+ struct kvm_sync_regs {
+       __u64 prefix;   /* prefix register */
+@@ -217,7 +218,9 @@ struct kvm_sync_regs {
+       };
+       __u8  reserved[512];    /* for future vector expansion */
+       __u32 fpc;              /* valid on KVM_SYNC_VRS or KVM_SYNC_FPRS */
+-      __u8 padding[52];       /* riccb needs to be 64byte aligned */
++      __u8 bpbc : 1;          /* bp mode */
++      __u8 reserved2 : 7;
++      __u8 padding1[51];      /* riccb needs to be 64byte aligned */
+       __u8 riccb[64];         /* runtime instrumentation controls block */
+ };
+--- a/tools/arch/x86/include/asm/cpufeatures.h
++++ b/tools/arch/x86/include/asm/cpufeatures.h
+@@ -12,7 +12,7 @@
+ /*
+  * Defines x86 CPU feature bits
+  */
+-#define NCAPINTS      18      /* N 32-bit words worth of info */
++#define NCAPINTS      19      /* N 32-bit words worth of info */
+ #define NBUGINTS      1       /* N 32-bit bug flags */
+ /*
+@@ -189,17 +189,32 @@
+ #define X86_FEATURE_CPB               ( 7*32+ 2) /* AMD Core Performance Boost */
+ #define X86_FEATURE_EPB               ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
++#define X86_FEATURE_INVPCID_SINGLE ( 7*32+ 4) /* Effectively INVPCID && CR4.PCIDE=1 */
+ #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */
+ #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
+-#define X86_FEATURE_INTEL_PT  ( 7*32+15) /* Intel Processor Trace */
+-#define X86_FEATURE_AVX512_4VNNIW (7*32+16) /* AVX-512 Neural Network Instructions */
+-#define X86_FEATURE_AVX512_4FMAPS (7*32+17) /* AVX-512 Multiply Accumulation Single precision */
++#define X86_FEATURE_RETPOLINE ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
++#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */
++
++#define X86_FEATURE_MSR_SPEC_CTRL ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */
++#define X86_FEATURE_SSBD      ( 7*32+17) /* Speculative Store Bypass Disable */
++
++#define X86_FEATURE_RSB_CTXSW ( 7*32+19) /* "" Fill RSB on context switches */
+ /* Because the ALTERNATIVE scheme is for members of the X86_FEATURE club... */
+ #define X86_FEATURE_KAISER    ( 7*32+31) /* CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */
++#define X86_FEATURE_USE_IBPB  ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */
++#define X86_FEATURE_USE_IBRS_FW       ( 7*32+22) /* "" Use IBRS during runtime firmware calls */
++#define X86_FEATURE_SPEC_STORE_BYPASS_DISABLE ( 7*32+23) /* "" Disable Speculative Store Bypass. */
++#define X86_FEATURE_LS_CFG_SSBD       ( 7*32+24) /* "" AMD SSBD implementation */
++#define X86_FEATURE_IBRS      ( 7*32+25) /* Indirect Branch Restricted Speculation */
++#define X86_FEATURE_IBPB      ( 7*32+26) /* Indirect Branch Prediction Barrier */
++#define X86_FEATURE_STIBP     ( 7*32+27) /* Single Thread Indirect Branch Predictors */
++#define X86_FEATURE_ZEN               ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */
++
++
+ /* Virtualization flags: Linux defined, word 8 */
+ #define X86_FEATURE_TPR_SHADOW  ( 8*32+ 0) /* Intel TPR Shadow */
+ #define X86_FEATURE_VNMI        ( 8*32+ 1) /* Intel Virtual NMI */
+@@ -231,6 +246,7 @@
+ #define X86_FEATURE_SMAP      ( 9*32+20) /* Supervisor Mode Access Prevention */
+ #define X86_FEATURE_CLFLUSHOPT        ( 9*32+23) /* CLFLUSHOPT instruction */
+ #define X86_FEATURE_CLWB      ( 9*32+24) /* CLWB instruction */
++#define X86_FEATURE_INTEL_PT  ( 9*32+25) /* Intel Processor Trace */
+ #define X86_FEATURE_AVX512PF  ( 9*32+26) /* AVX-512 Prefetch */
+ #define X86_FEATURE_AVX512ER  ( 9*32+27) /* AVX-512 Exponential and Reciprocal */
+ #define X86_FEATURE_AVX512CD  ( 9*32+28) /* AVX-512 Conflict Detection */
+@@ -255,6 +271,10 @@
+ /* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */
+ #define X86_FEATURE_CLZERO    (13*32+0) /* CLZERO instruction */
+ #define X86_FEATURE_IRPERF    (13*32+1) /* Instructions Retired Count */
++#define X86_FEATURE_AMD_IBPB  (13*32+12) /* Indirect Branch Prediction Barrier */
++#define X86_FEATURE_AMD_IBRS  (13*32+14) /* Indirect Branch Restricted Speculation */
++#define X86_FEATURE_AMD_STIBP (13*32+15) /* Single Thread Indirect Branch Predictors */
++#define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */
+ /* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */
+ #define X86_FEATURE_DTHERM    (14*32+ 0) /* Digital Thermal Sensor */
+@@ -290,6 +310,16 @@
+ #define X86_FEATURE_SUCCOR    (17*32+1) /* Uncorrectable error containment and recovery */
+ #define X86_FEATURE_SMCA      (17*32+3) /* Scalable MCA */
++
++/* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */
++#define X86_FEATURE_AVX512_4VNNIW     (18*32+ 2) /* AVX-512 Neural Network Instructions */
++#define X86_FEATURE_AVX512_4FMAPS     (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */
++#define X86_FEATURE_PCONFIG           (18*32+18) /* Intel PCONFIG */
++#define X86_FEATURE_SPEC_CTRL         (18*32+26) /* "" Speculation Control (IBRS + IBPB) */
++#define X86_FEATURE_INTEL_STIBP               (18*32+27) /* "" Single Thread Indirect Branch Predictors */
++#define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */
++#define X86_FEATURE_SPEC_CTRL_SSBD    (18*32+31) /* "" Speculative Store Bypass Disable */
++
+ /*
+  * BUG word(s)
+  */
+@@ -314,4 +344,10 @@
+ #define X86_BUG_NULL_SEG      X86_BUG(10) /* Nulling a selector preserves the base */
+ #define X86_BUG_SWAPGS_FENCE  X86_BUG(11) /* SWAPGS without input dep on GS */
+ #define X86_BUG_MONITOR               X86_BUG(12) /* IPI required to wake up remote CPU */
++#define X86_BUG_AMD_E400      X86_BUG(13) /* CPU is among the affected by Erratum 400 */
++#define X86_BUG_CPU_MELTDOWN  X86_BUG(14) /* CPU is affected by meltdown attack and needs kernel page table isolation */
++#define X86_BUG_SPECTRE_V1    X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */
++#define X86_BUG_SPECTRE_V2    X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */
++#define X86_BUG_SPEC_STORE_BYPASS X86_BUG(17) /* CPU is affected by speculative store bypass attack */
++
+ #endif /* _ASM_X86_CPUFEATURES_H */
+--- a/tools/arch/x86/include/asm/disabled-features.h
++++ b/tools/arch/x86/include/asm/disabled-features.h
+@@ -21,11 +21,13 @@
+ # define DISABLE_K6_MTRR      (1<<(X86_FEATURE_K6_MTRR & 31))
+ # define DISABLE_CYRIX_ARR    (1<<(X86_FEATURE_CYRIX_ARR & 31))
+ # define DISABLE_CENTAUR_MCR  (1<<(X86_FEATURE_CENTAUR_MCR & 31))
++# define DISABLE_PCID         0
+ #else
+ # define DISABLE_VME          0
+ # define DISABLE_K6_MTRR      0
+ # define DISABLE_CYRIX_ARR    0
+ # define DISABLE_CENTAUR_MCR  0
++# define DISABLE_PCID         (1<<(X86_FEATURE_PCID & 31))
+ #endif /* CONFIG_X86_64 */
+ #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
+@@ -43,7 +45,7 @@
+ #define DISABLED_MASK1        0
+ #define DISABLED_MASK2        0
+ #define DISABLED_MASK3        (DISABLE_CYRIX_ARR|DISABLE_CENTAUR_MCR|DISABLE_K6_MTRR)
+-#define DISABLED_MASK4        0
++#define DISABLED_MASK4        (DISABLE_PCID)
+ #define DISABLED_MASK5        0
+ #define DISABLED_MASK6        0
+ #define DISABLED_MASK7        0
+@@ -57,6 +59,7 @@
+ #define DISABLED_MASK15       0
+ #define DISABLED_MASK16       (DISABLE_PKU|DISABLE_OSPKE)
+ #define DISABLED_MASK17       0
+-#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18)
++#define DISABLED_MASK18       0
++#define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
+ #endif /* _ASM_X86_DISABLED_FEATURES_H */
+--- a/tools/arch/x86/include/asm/required-features.h
++++ b/tools/arch/x86/include/asm/required-features.h
+@@ -100,6 +100,7 @@
+ #define REQUIRED_MASK15       0
+ #define REQUIRED_MASK16       0
+ #define REQUIRED_MASK17       0
+-#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 18)
++#define REQUIRED_MASK18       0
++#define REQUIRED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 19)
+ #endif /* _ASM_X86_REQUIRED_FEATURES_H */
+--- a/tools/include/uapi/asm-generic/mman-common.h
++++ b/tools/include/uapi/asm-generic/mman-common.h
+@@ -72,4 +72,9 @@
+ #define MAP_HUGE_SHIFT        26
+ #define MAP_HUGE_MASK 0x3f
++#define PKEY_DISABLE_ACCESS   0x1
++#define PKEY_DISABLE_WRITE    0x2
++#define PKEY_ACCESS_MASK      (PKEY_DISABLE_ACCESS |\
++                               PKEY_DISABLE_WRITE)
++
+ #endif /* __ASM_GENERIC_MMAN_COMMON_H */
+--- a/tools/include/uapi/linux/bpf.h
++++ b/tools/include/uapi/linux/bpf.h
+@@ -95,6 +95,7 @@ enum bpf_prog_type {
+       BPF_PROG_TYPE_SCHED_ACT,
+       BPF_PROG_TYPE_TRACEPOINT,
+       BPF_PROG_TYPE_XDP,
++      BPF_PROG_TYPE_PERF_EVENT,
+ };
+ #define BPF_PSEUDO_MAP_FD     1
+@@ -375,6 +376,56 @@ enum bpf_func_id {
+        */
+       BPF_FUNC_probe_write_user,
++      /**
++       * bpf_current_task_under_cgroup(map, index) - Check cgroup2 membership of current task
++       * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type
++       * @index: index of the cgroup in the bpf_map
++       * Return:
++       *   == 0 current failed the cgroup2 descendant test
++       *   == 1 current succeeded the cgroup2 descendant test
++       *    < 0 error
++       */
++      BPF_FUNC_current_task_under_cgroup,
++
++      /**
++       * bpf_skb_change_tail(skb, len, flags)
++       * The helper will resize the skb to the given new size,
++       * to be used f.e. with control messages.
++       * @skb: pointer to skb
++       * @len: new skb length
++       * @flags: reserved
++       * Return: 0 on success or negative error
++       */
++      BPF_FUNC_skb_change_tail,
++
++      /**
++       * bpf_skb_pull_data(skb, len)
++       * The helper will pull in non-linear data in case the
++       * skb is non-linear and not all of len are part of the
++       * linear section. Only needed for read/write with direct
++       * packet access.
++       * @skb: pointer to skb
++       * @len: len to make read/writeable
++       * Return: 0 on success or negative error
++       */
++      BPF_FUNC_skb_pull_data,
++
++      /**
++       * bpf_csum_update(skb, csum)
++       * Adds csum into skb->csum in case of CHECKSUM_COMPLETE.
++       * @skb: pointer to skb
++       * @csum: csum to add
++       * Return: csum on success or negative error
++       */
++      BPF_FUNC_csum_update,
++
++      /**
++       * bpf_set_hash_invalid(skb)
++       * Invalidate current skb>hash.
++       * @skb: pointer to skb
++       */
++      BPF_FUNC_set_hash_invalid,
++
+       __BPF_FUNC_MAX_ID,
+ };
+--- a/tools/include/uapi/linux/fcntl.h
++++ b/tools/include/uapi/linux/fcntl.h
+@@ -63,10 +63,5 @@
+ #define AT_NO_AUTOMOUNT               0x800   /* Suppress terminal automount traversal */
+ #define AT_EMPTY_PATH         0x1000  /* Allow empty relative pathname */
+-#define AT_STATX_SYNC_TYPE    0x6000  /* Type of synchronisation required from statx() */
+-#define AT_STATX_SYNC_AS_STAT 0x0000  /* - Do whatever stat() does */
+-#define AT_STATX_FORCE_SYNC   0x2000  /* - Force the attributes to be sync'd with the server */
+-#define AT_STATX_DONT_SYNC    0x4000  /* - Don't sync attributes with the server */
+-
+ #endif /* _UAPI_LINUX_FCNTL_H */
+--- a/tools/include/uapi/linux/stat.h
++++ b/tools/include/uapi/linux/stat.h
+@@ -1,7 +1,6 @@
+ #ifndef _UAPI_LINUX_STAT_H
+ #define _UAPI_LINUX_STAT_H
+-#include <linux/types.h>
+ #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+@@ -42,135 +41,5 @@
+ #endif
+-/*
+- * Timestamp structure for the timestamps in struct statx.
+- *
+- * tv_sec holds the number of seconds before (negative) or after (positive)
+- * 00:00:00 1st January 1970 UTC.
+- *
+- * tv_nsec holds a number of nanoseconds before (0..-999,999,999 if tv_sec is
+- * negative) or after (0..999,999,999 if tv_sec is positive) the tv_sec time.
+- *
+- * Note that if both tv_sec and tv_nsec are non-zero, then the two values must
+- * either be both positive or both negative.
+- *
+- * __reserved is held in case we need a yet finer resolution.
+- */
+-struct statx_timestamp {
+-      __s64   tv_sec;
+-      __s32   tv_nsec;
+-      __s32   __reserved;
+-};
+-
+-/*
+- * Structures for the extended file attribute retrieval system call
+- * (statx()).
+- *
+- * The caller passes a mask of what they're specifically interested in as a
+- * parameter to statx().  What statx() actually got will be indicated in
+- * st_mask upon return.
+- *
+- * For each bit in the mask argument:
+- *
+- * - if the datum is not supported:
+- *
+- *   - the bit will be cleared, and
+- *
+- *   - the datum will be set to an appropriate fabricated value if one is
+- *     available (eg. CIFS can take a default uid and gid), otherwise
+- *
+- *   - the field will be cleared;
+- *
+- * - otherwise, if explicitly requested:
+- *
+- *   - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is
+- *     set or if the datum is considered out of date, and
+- *
+- *   - the field will be filled in and the bit will be set;
+- *
+- * - otherwise, if not requested, but available in approximate form without any
+- *   effort, it will be filled in anyway, and the bit will be set upon return
+- *   (it might not be up to date, however, and no attempt will be made to
+- *   synchronise the internal state first);
+- *
+- * - otherwise the field and the bit will be cleared before returning.
+- *
+- * Items in STATX_BASIC_STATS may be marked unavailable on return, but they
+- * will have values installed for compatibility purposes so that stat() and
+- * co. can be emulated in userspace.
+- */
+-struct statx {
+-      /* 0x00 */
+-      __u32   stx_mask;       /* What results were written [uncond] */
+-      __u32   stx_blksize;    /* Preferred general I/O size [uncond] */
+-      __u64   stx_attributes; /* Flags conveying information about the file [uncond] */
+-      /* 0x10 */
+-      __u32   stx_nlink;      /* Number of hard links */
+-      __u32   stx_uid;        /* User ID of owner */
+-      __u32   stx_gid;        /* Group ID of owner */
+-      __u16   stx_mode;       /* File mode */
+-      __u16   __spare0[1];
+-      /* 0x20 */
+-      __u64   stx_ino;        /* Inode number */
+-      __u64   stx_size;       /* File size */
+-      __u64   stx_blocks;     /* Number of 512-byte blocks allocated */
+-      __u64   __spare1[1];
+-      /* 0x40 */
+-      struct statx_timestamp  stx_atime;      /* Last access time */
+-      struct statx_timestamp  stx_btime;      /* File creation time */
+-      struct statx_timestamp  stx_ctime;      /* Last attribute change time */
+-      struct statx_timestamp  stx_mtime;      /* Last data modification time */
+-      /* 0x80 */
+-      __u32   stx_rdev_major; /* Device ID of special file [if bdev/cdev] */
+-      __u32   stx_rdev_minor;
+-      __u32   stx_dev_major;  /* ID of device containing file [uncond] */
+-      __u32   stx_dev_minor;
+-      /* 0x90 */
+-      __u64   __spare2[14];   /* Spare space for future expansion */
+-      /* 0x100 */
+-};
+-
+-/*
+- * Flags to be stx_mask
+- *
+- * Query request/result mask for statx() and struct statx::stx_mask.
+- *
+- * These bits should be set in the mask argument of statx() to request
+- * particular items when calling statx().
+- */
+-#define STATX_TYPE            0x00000001U     /* Want/got stx_mode & S_IFMT */
+-#define STATX_MODE            0x00000002U     /* Want/got stx_mode & ~S_IFMT */
+-#define STATX_NLINK           0x00000004U     /* Want/got stx_nlink */
+-#define STATX_UID             0x00000008U     /* Want/got stx_uid */
+-#define STATX_GID             0x00000010U     /* Want/got stx_gid */
+-#define STATX_ATIME           0x00000020U     /* Want/got stx_atime */
+-#define STATX_MTIME           0x00000040U     /* Want/got stx_mtime */
+-#define STATX_CTIME           0x00000080U     /* Want/got stx_ctime */
+-#define STATX_INO             0x00000100U     /* Want/got stx_ino */
+-#define STATX_SIZE            0x00000200U     /* Want/got stx_size */
+-#define STATX_BLOCKS          0x00000400U     /* Want/got stx_blocks */
+-#define STATX_BASIC_STATS     0x000007ffU     /* The stuff in the normal stat struct */
+-#define STATX_BTIME           0x00000800U     /* Want/got stx_btime */
+-#define STATX_ALL             0x00000fffU     /* All currently supported flags */
+-
+-/*
+- * Attributes to be found in stx_attributes
+- *
+- * These give information about the features or the state of a file that might
+- * be of use to ordinary userspace programs such as GUIs or ls rather than
+- * specialised tools.
+- *
+- * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS
+- * semantically.  Where possible, the numerical value is picked to correspond
+- * also.
+- */
+-#define STATX_ATTR_COMPRESSED         0x00000004 /* [I] File is compressed by the fs */
+-#define STATX_ATTR_IMMUTABLE          0x00000010 /* [I] File is marked immutable */
+-#define STATX_ATTR_APPEND             0x00000020 /* [I] File is append-only */
+-#define STATX_ATTR_NODUMP             0x00000040 /* [I] File is not to be dumped */
+-#define STATX_ATTR_ENCRYPTED          0x00000800 /* [I] File requires key to decrypt in fs */
+-
+-#define STATX_ATTR_AUTOMOUNT          0x00001000 /* Dir: Automount trigger */
+-
+ #endif /* _UAPI_LINUX_STAT_H */
+--- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
++++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+@@ -335,6 +335,9 @@
+ 326   common  copy_file_range         sys_copy_file_range
+ 327   64      preadv2                 sys_preadv2
+ 328   64      pwritev2                sys_pwritev2
++329   common  pkey_mprotect           sys_pkey_mprotect
++330   common  pkey_alloc              sys_pkey_alloc
++331   common  pkey_free               sys_pkey_free
+ #
+ # x32-specific system call numbers start at 512 to avoid cache impact
+@@ -374,5 +377,5 @@
+ 543   x32     io_setup                compat_sys_io_setup
+ 544   x32     io_submit               compat_sys_io_submit
+ 545   x32     execveat                compat_sys_execveat/ptregs
+-534   x32     preadv2                 compat_sys_preadv2
+-535   x32     pwritev2                compat_sys_pwritev2
++546   x32     preadv2                 compat_sys_preadv64v2
++547   x32     pwritev2                compat_sys_pwritev64v2
diff --git a/objtool-4.9/radix-tree-test-suite-remove-types.h.patch b/objtool-4.9/radix-tree-test-suite-remove-types.h.patch
new file mode 100644 (file)
index 0000000..d4bc8d4
--- /dev/null
@@ -0,0 +1,49 @@
+From 12ea65390bd5a46f8a70f068eb0d48922576a781 Mon Sep 17 00:00:00 2001
+From: Matthew Wilcox <mawilcox@microsoft.com>
+Date: Fri, 16 Dec 2016 14:53:45 -0500
+Subject: radix tree test suite: Remove types.h
+
+From: Matthew Wilcox <mawilcox@microsoft.com>
+
+commit 12ea65390bd5a46f8a70f068eb0d48922576a781 upstream.
+
+Move the pieces we still need to tools/include and update a few implicit
+includes.
+
+Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
+[ Just take the tools/include/linux/* portions of this patch - gregkh]
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/compiler.h |    4 ++++
+ tools/include/linux/spinlock.h |    5 +++++
+ 2 files changed, 9 insertions(+)
+
+--- a/tools/include/linux/compiler.h
++++ b/tools/include/linux/compiler.h
+@@ -25,6 +25,8 @@
+ #endif
+ #define __user
++#define __rcu
++#define __read_mostly
+ #ifndef __attribute_const__
+ # define __attribute_const__
+@@ -54,6 +56,8 @@
+ # define unlikely(x)          __builtin_expect(!!(x), 0)
+ #endif
++#define uninitialized_var(x) x = *(&(x))
++
+ #define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+ #include <linux/types.h>
+--- /dev/null
++++ b/tools/include/linux/spinlock.h
+@@ -0,0 +1,5 @@
++#define spinlock_t            pthread_mutex_t
++#define DEFINE_SPINLOCK(x)    pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER;
++
++#define spin_lock_irqsave(x, f)               (void)f, pthread_mutex_lock(x)
++#define spin_unlock_irqrestore(x, f)  (void)f, pthread_mutex_unlock(x)
diff --git a/objtool-4.9/series b/objtool-4.9/series
new file mode 100644 (file)
index 0000000..082f84a
--- /dev/null
@@ -0,0 +1,29 @@
+objtool-improve-detection-of-bug-and-other-dead-ends.patch
+objtool-move-checking-code-to-check.c.patch
+tools-lib-add-for_each_clear_bit-macro.patch
+tools-add-more-bitmap-functions.patch
+tools-enable-endian-checks-for-all-sparse-builds.patch
+tools-include-introduce-linux-compiler-gcc.h.patch
+radix-tree-test-suite-remove-types.h.patch
+tools-include-adopt-__compiletime_error.patch
+tools-include-introduce-atomic_cmpxchg_-relaxed-release.patch
+tools-include-add-uint_max-def-to-kernel.h.patch
+tools-include-adopt-kernel-s-refcount.h.patch
+perf-tools-force-fixdep-compilation-at-the-start-of-the-build.patch
+perf-tools-move-headers-check-into-bash-script.patch
+tools-include-uapi-grab-copies-of-stat.h-and-fcntl.h.patch
+tools-include-introduce-linux-bug.h-from-the-kernel-sources.patch
+tools-include-adopt-__same_type-and-__must_be_array-from-the-kernel.patch
+tools-include-move-array_size-to-linux-kernel.h.patch
+tools-include-drop-array_size-definition-from-linux-hashtable.h.patch
+tools-include-include-missing-headers-for-fls-and-types-in-linux-log2.h.patch
+objdiff.patch
+objtool-support-gcc-8-s-cold-subfunctions.patch
+objtool-support-gcc-8-switch-tables.patch
+objtool-detect-rip-relative-switch-table-references.patch
+objtool-detect-rip-relative-switch-table-references-part-2.patch
+objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch
+objtool-x86-add-several-functions-and-files-to-the-objtool-whitelist.patch
+perf_headers_sync.patch
+objtool_headers_sync.patch
+xen-fixup.patch
diff --git a/objtool-4.9/tools-add-more-bitmap-functions.patch b/objtool-4.9/tools-add-more-bitmap-functions.patch
new file mode 100644 (file)
index 0000000..b7c49c4
--- /dev/null
@@ -0,0 +1,65 @@
+From b328daf3b7130098b105c18bdae694ddaad5b6e3 Mon Sep 17 00:00:00 2001
+From: Matthew Wilcox <willy@linux.intel.com>
+Date: Wed, 14 Dec 2016 15:08:26 -0800
+Subject: tools: add more bitmap functions
+
+From: Matthew Wilcox <willy@linux.intel.com>
+
+commit b328daf3b7130098b105c18bdae694ddaad5b6e3 upstream.
+
+I need the following functions for the radix tree:
+
+  bitmap_fill
+  bitmap_empty
+  bitmap_full
+
+Copy the implementations from include/linux/bitmap.h
+
+Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
+Tested-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Konstantin Khlebnikov <koct9i@gmail.com>
+Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
+Cc: Matthew Wilcox <mawilcox@microsoft.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/bitmap.h |   26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+--- a/tools/include/linux/bitmap.h
++++ b/tools/include/linux/bitmap.h
+@@ -35,6 +35,32 @@ static inline void bitmap_zero(unsigned
+       }
+ }
++static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
++{
++      unsigned int nlongs = BITS_TO_LONGS(nbits);
++      if (!small_const_nbits(nbits)) {
++              unsigned int len = (nlongs - 1) * sizeof(unsigned long);
++              memset(dst, 0xff,  len);
++      }
++      dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
++}
++
++static inline int bitmap_empty(const unsigned long *src, unsigned nbits)
++{
++      if (small_const_nbits(nbits))
++              return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
++
++      return find_first_bit(src, nbits) == nbits;
++}
++
++static inline int bitmap_full(const unsigned long *src, unsigned int nbits)
++{
++      if (small_const_nbits(nbits))
++              return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
++
++      return find_first_zero_bit(src, nbits) == nbits;
++}
++
+ static inline int bitmap_weight(const unsigned long *src, int nbits)
+ {
+       if (small_const_nbits(nbits))
diff --git a/objtool-4.9/tools-enable-endian-checks-for-all-sparse-builds.patch b/objtool-4.9/tools-enable-endian-checks-for-all-sparse-builds.patch
new file mode 100644 (file)
index 0000000..c2df555
--- /dev/null
@@ -0,0 +1,33 @@
+From 376a5fb34b04524af501a0c5979c5920be940e05 Mon Sep 17 00:00:00 2001
+From: "Michael S. Tsirkin" <mst@redhat.com>
+Date: Sun, 11 Dec 2016 06:27:21 +0200
+Subject: tools: enable endian checks for all sparse builds
+
+From: Michael S. Tsirkin <mst@redhat.com>
+
+commit 376a5fb34b04524af501a0c5979c5920be940e05 upstream.
+
+We dropped need for __CHECK_ENDIAN__ for linux,
+this mirrors this for tools.
+
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/types.h |    4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/tools/include/linux/types.h
++++ b/tools/include/linux/types.h
+@@ -42,11 +42,7 @@ typedef __s8  s8;
+ #else
+ #define __bitwise__
+ #endif
+-#ifdef __CHECK_ENDIAN__
+ #define __bitwise __bitwise__
+-#else
+-#define __bitwise
+-#endif
+ #define __force
+ #define __user
diff --git a/objtool-4.9/tools-include-add-uint_max-def-to-kernel.h.patch b/objtool-4.9/tools-include-add-uint_max-def-to-kernel.h.patch
new file mode 100644 (file)
index 0000000..fafc8df
--- /dev/null
@@ -0,0 +1,39 @@
+From eaa75b5117d52adf1efd3c6c3fb4bd8f97de648b Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Wed, 22 Feb 2017 17:42:40 -0300
+Subject: tools include: Add UINT_MAX def to kernel.h
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit eaa75b5117d52adf1efd3c6c3fb4bd8f97de648b upstream.
+
+The kernel has it and some files we got from there would require us
+including the userland header for that, so add it conditionally.
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Elena Reshetova <elena.reshetova@intel.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-gmwyal7c9vzzttlyk6u59rzn@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/kernel.h |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/tools/include/linux/kernel.h
++++ b/tools/include/linux/kernel.h
+@@ -5,6 +5,10 @@
+ #include <stddef.h>
+ #include <assert.h>
++#ifndef UINT_MAX
++#define UINT_MAX      (~0U)
++#endif
++
+ #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+ #define PERF_ALIGN(x, a)      __PERF_ALIGN_MASK(x, (typeof(x))(a)-1)
diff --git a/objtool-4.9/tools-include-adopt-__compiletime_error.patch b/objtool-4.9/tools-include-adopt-__compiletime_error.patch
new file mode 100644 (file)
index 0000000..16ade60
--- /dev/null
@@ -0,0 +1,52 @@
+From 4900653829175f60356efc279695bb23c59483c3 Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Wed, 22 Feb 2017 16:48:24 -0300
+Subject: tools include: Adopt __compiletime_error
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit 4900653829175f60356efc279695bb23c59483c3 upstream.
+
+From the kernel, get the gcc one and provide the fallback so that we can
+continue build with other compilers, such as with clang.
+
+Will be used by tools/arch/x86/include/asm/cmpxchg.h.
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Elena Reshetova <elena.reshetova@intel.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-pecgz6efai4a9euuk4rxuotr@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/compiler-gcc.h |    4 ++++
+ tools/include/linux/compiler.h     |    4 ++++
+ 2 files changed, 8 insertions(+)
+
+--- a/tools/include/linux/compiler-gcc.h
++++ b/tools/include/linux/compiler-gcc.h
+@@ -12,3 +12,7 @@
+ #if GCC_VERSION >= 70000 && !defined(__CHECKER__)
+ # define __fallthrough __attribute__ ((fallthrough))
+ #endif
++
++#if GCC_VERSION >= 40300
++# define __compiletime_error(message) __attribute__((error(message)))
++#endif /* GCC_VERSION >= 40300 */
+--- a/tools/include/linux/compiler.h
++++ b/tools/include/linux/compiler.h
+@@ -5,6 +5,10 @@
+ #include <linux/compiler-gcc.h>
+ #endif
++#ifndef __compiletime_error
++# define __compiletime_error(message)
++#endif
++
+ /* Optimization barrier */
+ /* The "volatile" is due to gcc bugs */
+ #define barrier() __asm__ __volatile__("": : :"memory")
diff --git a/objtool-4.9/tools-include-adopt-__same_type-and-__must_be_array-from-the-kernel.patch b/objtool-4.9/tools-include-adopt-__same_type-and-__must_be_array-from-the-kernel.patch
new file mode 100644 (file)
index 0000000..85104f8
--- /dev/null
@@ -0,0 +1,49 @@
+From f6441aff8946f7fd6ab730d7eb9eba18a9ebeba4 Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Mon, 17 Apr 2017 11:25:00 -0300
+Subject: tools include: Adopt __same_type() and __must_be_array() from the kernel
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit f6441aff8946f7fd6ab730d7eb9eba18a9ebeba4 upstream.
+
+Will be used to adopt the more stringent version of ARRAY_SIZE(), the
+one in the kernel sources.
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-d85dpvay1hoqscpezlntyd8x@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/compiler-gcc.h |    3 +++
+ tools/include/linux/compiler.h     |    5 +++++
+ 2 files changed, 8 insertions(+)
+
+--- a/tools/include/linux/compiler-gcc.h
++++ b/tools/include/linux/compiler-gcc.h
+@@ -16,3 +16,6 @@
+ #if GCC_VERSION >= 40300
+ # define __compiletime_error(message) __attribute__((error(message)))
+ #endif /* GCC_VERSION >= 40300 */
++
++/* &a[0] degrades to a pointer: a different type from an array */
++#define __must_be_array(a)    BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
+--- a/tools/include/linux/compiler.h
++++ b/tools/include/linux/compiler.h
+@@ -17,6 +17,11 @@
+ # define __always_inline      inline __attribute__((always_inline))
+ #endif
++/* Are two types/vars the same type (ignoring qualifiers)? */
++#ifndef __same_type
++# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
++#endif
++
+ #ifdef __ANDROID__
+ /*
+  * FIXME: Big hammer to get rid of tons of:
diff --git a/objtool-4.9/tools-include-adopt-kernel-s-refcount.h.patch b/objtool-4.9/tools-include-adopt-kernel-s-refcount.h.patch
new file mode 100644 (file)
index 0000000..79d33db
--- /dev/null
@@ -0,0 +1,200 @@
+From 73a9bf95ed1c05698ecabe2f28c47aedfa61b52b Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Wed, 22 Feb 2017 17:00:53 -0300
+Subject: tools include: Adopt kernel's refcount.h
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit 73a9bf95ed1c05698ecabe2f28c47aedfa61b52b upstream.
+
+To aid in catching bugs when using atomics as a reference count.
+
+This is a trimmed down version with just what is used by tools/ at
+this point.
+
+After this, the patches submitted by Elena for tools/ doing the
+conversion from atomic_ to recount_ methods can be applied and tested.
+
+To activate it, buint perf with:
+
+  make DEBUG=1 -C tools/perf
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Elena Reshetova <elena.reshetova@intel.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-dqtxsumns9ov0l9r5x398f19@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/refcount.h |  151 +++++++++++++++++++++++++++++++++++++++++
+ tools/perf/MANIFEST            |    1 
+ 2 files changed, 152 insertions(+)
+
+--- /dev/null
++++ b/tools/include/linux/refcount.h
+@@ -0,0 +1,151 @@
++#ifndef _TOOLS_LINUX_REFCOUNT_H
++#define _TOOLS_LINUX_REFCOUNT_H
++
++/*
++ * Variant of atomic_t specialized for reference counts.
++ *
++ * The interface matches the atomic_t interface (to aid in porting) but only
++ * provides the few functions one should use for reference counting.
++ *
++ * It differs in that the counter saturates at UINT_MAX and will not move once
++ * there. This avoids wrapping the counter and causing 'spurious'
++ * use-after-free issues.
++ *
++ * Memory ordering rules are slightly relaxed wrt regular atomic_t functions
++ * and provide only what is strictly required for refcounts.
++ *
++ * The increments are fully relaxed; these will not provide ordering. The
++ * rationale is that whatever is used to obtain the object we're increasing the
++ * reference count on will provide the ordering. For locked data structures,
++ * its the lock acquire, for RCU/lockless data structures its the dependent
++ * load.
++ *
++ * Do note that inc_not_zero() provides a control dependency which will order
++ * future stores against the inc, this ensures we'll never modify the object
++ * if we did not in fact acquire a reference.
++ *
++ * The decrements will provide release order, such that all the prior loads and
++ * stores will be issued before, it also provides a control dependency, which
++ * will order us against the subsequent free().
++ *
++ * The control dependency is against the load of the cmpxchg (ll/sc) that
++ * succeeded. This means the stores aren't fully ordered, but this is fine
++ * because the 1->0 transition indicates no concurrency.
++ *
++ * Note that the allocator is responsible for ordering things between free()
++ * and alloc().
++ *
++ */
++
++#include <linux/atomic.h>
++#include <linux/kernel.h>
++
++#ifdef NDEBUG
++#define REFCOUNT_WARN(cond, str) (void)(cond)
++#define __refcount_check
++#else
++#define REFCOUNT_WARN(cond, str) BUG_ON(cond)
++#define __refcount_check      __must_check
++#endif
++
++typedef struct refcount_struct {
++      atomic_t refs;
++} refcount_t;
++
++#define REFCOUNT_INIT(n)      { .refs = ATOMIC_INIT(n), }
++
++static inline void refcount_set(refcount_t *r, unsigned int n)
++{
++      atomic_set(&r->refs, n);
++}
++
++static inline unsigned int refcount_read(const refcount_t *r)
++{
++      return atomic_read(&r->refs);
++}
++
++/*
++ * Similar to atomic_inc_not_zero(), will saturate at UINT_MAX and WARN.
++ *
++ * Provides no memory ordering, it is assumed the caller has guaranteed the
++ * object memory to be stable (RCU, etc.). It does provide a control dependency
++ * and thereby orders future stores. See the comment on top.
++ */
++static inline __refcount_check
++bool refcount_inc_not_zero(refcount_t *r)
++{
++      unsigned int old, new, val = atomic_read(&r->refs);
++
++      for (;;) {
++              new = val + 1;
++
++              if (!val)
++                      return false;
++
++              if (unlikely(!new))
++                      return true;
++
++              old = atomic_cmpxchg_relaxed(&r->refs, val, new);
++              if (old == val)
++                      break;
++
++              val = old;
++      }
++
++      REFCOUNT_WARN(new == UINT_MAX, "refcount_t: saturated; leaking memory.\n");
++
++      return true;
++}
++
++/*
++ * Similar to atomic_inc(), will saturate at UINT_MAX and WARN.
++ *
++ * Provides no memory ordering, it is assumed the caller already has a
++ * reference on the object, will WARN when this is not so.
++ */
++static inline void refcount_inc(refcount_t *r)
++{
++      REFCOUNT_WARN(!refcount_inc_not_zero(r), "refcount_t: increment on 0; use-after-free.\n");
++}
++
++/*
++ * Similar to atomic_dec_and_test(), it will WARN on underflow and fail to
++ * decrement when saturated at UINT_MAX.
++ *
++ * Provides release memory ordering, such that prior loads and stores are done
++ * before, and provides a control dependency such that free() must come after.
++ * See the comment on top.
++ */
++static inline __refcount_check
++bool refcount_sub_and_test(unsigned int i, refcount_t *r)
++{
++      unsigned int old, new, val = atomic_read(&r->refs);
++
++      for (;;) {
++              if (unlikely(val == UINT_MAX))
++                      return false;
++
++              new = val - i;
++              if (new > val) {
++                      REFCOUNT_WARN(new > val, "refcount_t: underflow; use-after-free.\n");
++                      return false;
++              }
++
++              old = atomic_cmpxchg_release(&r->refs, val, new);
++              if (old == val)
++                      break;
++
++              val = old;
++      }
++
++      return !new;
++}
++
++static inline __refcount_check
++bool refcount_dec_and_test(refcount_t *r)
++{
++      return refcount_sub_and_test(1, r);
++}
++
++
++#endif /* _ATOMIC_LINUX_REFCOUNT_H */
+--- a/tools/perf/MANIFEST
++++ b/tools/perf/MANIFEST
+@@ -78,6 +78,7 @@ tools/include/uapi/linux/perf_event.h
+ tools/include/linux/poison.h
+ tools/include/linux/rbtree.h
+ tools/include/linux/rbtree_augmented.h
++tools/include/linux/refcount.h
+ tools/include/linux/string.h
+ tools/include/linux/stringify.h
+ tools/include/linux/types.h
diff --git a/objtool-4.9/tools-include-drop-array_size-definition-from-linux-hashtable.h.patch b/objtool-4.9/tools-include-drop-array_size-definition-from-linux-hashtable.h.patch
new file mode 100644 (file)
index 0000000..62b5d69
--- /dev/null
@@ -0,0 +1,40 @@
+From 68289cbd83eaa20faef7cc818121bc8e769065de Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Mon, 17 Apr 2017 12:01:36 -0300
+Subject: tools include: Drop ARRAY_SIZE() definition from linux/hashtable.h
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit 68289cbd83eaa20faef7cc818121bc8e769065de upstream.
+
+As tools/include/linux/kernel.h has it now, with the goodies present in
+the kernel.h counterpart, i.e. checking that the parameter is an array
+at build time.
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Josh Poimboeuf <jpoimboe@redhat.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-v0b41ivu6z6dyugbq9ffa9ez@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/hashtable.h |    4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/tools/include/linux/hashtable.h
++++ b/tools/include/linux/hashtable.h
+@@ -13,10 +13,6 @@
+ #include <linux/hash.h>
+ #include <linux/log2.h>
+-#ifndef ARRAY_SIZE
+-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+-#endif
+-
+ #define DEFINE_HASHTABLE(name, bits)                                          \
+       struct hlist_head name[1 << (bits)] =                                   \
+                       { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
diff --git a/objtool-4.9/tools-include-include-missing-headers-for-fls-and-types-in-linux-log2.h.patch b/objtool-4.9/tools-include-include-missing-headers-for-fls-and-types-in-linux-log2.h.patch
new file mode 100644 (file)
index 0000000..25c6d98
--- /dev/null
@@ -0,0 +1,34 @@
+From a12a4e023a55f058178afea1ada3ce7bf4db94c3 Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Mon, 17 Apr 2017 16:22:30 -0300
+Subject: tools include: Include missing headers for fls() and types in linux/log2.h
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit a12a4e023a55f058178afea1ada3ce7bf4db94c3 upstream.
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-7wj865zidu5ylf87i6i7v6z7@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/log2.h |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/tools/include/linux/log2.h
++++ b/tools/include/linux/log2.h
+@@ -12,6 +12,9 @@
+ #ifndef _TOOLS_LINUX_LOG2_H
+ #define _TOOLS_LINUX_LOG2_H
++#include <linux/bitops.h>
++#include <linux/types.h>
++
+ /*
+  * non-constant log of base 2 calculators
+  * - the arch may override these in asm/bitops.h if they can be implemented
diff --git a/objtool-4.9/tools-include-introduce-atomic_cmpxchg_-relaxed-release.patch b/objtool-4.9/tools-include-introduce-atomic_cmpxchg_-relaxed-release.patch
new file mode 100644 (file)
index 0000000..7b59824
--- /dev/null
@@ -0,0 +1,38 @@
+From 2bcdeadbc094b4f6511aedea1e5b8052bf0cc89c Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Wed, 22 Feb 2017 16:57:53 -0300
+Subject: tools include: Introduce atomic_cmpxchg_{relaxed,release}()
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit 2bcdeadbc094b4f6511aedea1e5b8052bf0cc89c upstream.
+
+Will be used by refcnt.h
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Elena Reshetova <elena.reshetova@intel.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-jszriruqfqpez1bkivwfj6qb@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/atomic.h |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/tools/include/linux/atomic.h
++++ b/tools/include/linux/atomic.h
+@@ -3,4 +3,10 @@
+ #include <asm/atomic.h>
++/* atomic_cmpxchg_relaxed */
++#ifndef atomic_cmpxchg_relaxed
++#define  atomic_cmpxchg_relaxed               atomic_cmpxchg
++#define  atomic_cmpxchg_release         atomic_cmpxchg
++#endif /* atomic_cmpxchg_relaxed */
++
+ #endif /* __TOOLS_LINUX_ATOMIC_H */
diff --git a/objtool-4.9/tools-include-introduce-linux-bug.h-from-the-kernel-sources.patch b/objtool-4.9/tools-include-introduce-linux-bug.h-from-the-kernel-sources.patch
new file mode 100644 (file)
index 0000000..d25c20f
--- /dev/null
@@ -0,0 +1,49 @@
+From 379d61b1c7d42512cded04d372f15a7e725db9e1 Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Mon, 17 Apr 2017 11:23:41 -0300
+Subject: tools include: Introduce linux/bug.h, from the kernel sources
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit 379d61b1c7d42512cded04d372f15a7e725db9e1 upstream.
+
+With just what we will need in the upcoming changesets, the
+BUILD_BUG_ON_ZERO() definition.
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-lw8zg7x6ttwcvqhp90mwe3vo@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/bug.h |   10 ++++++++++
+ tools/perf/MANIFEST       |    1 +
+ 2 files changed, 11 insertions(+)
+
+--- /dev/null
++++ b/tools/include/linux/bug.h
+@@ -0,0 +1,10 @@
++#ifndef _TOOLS_PERF_LINUX_BUG_H
++#define _TOOLS_PERF_LINUX_BUG_H
++
++/* Force a compilation error if condition is true, but also produce a
++   result (of value 0 and type size_t), so the expression can be used
++   e.g. in a structure initializer (or where-ever else comma expressions
++   aren't permitted). */
++#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
++
++#endif        /* _TOOLS_PERF_LINUX_BUG_H */
+--- a/tools/perf/MANIFEST
++++ b/tools/perf/MANIFEST
+@@ -63,6 +63,7 @@ tools/include/linux/bitops.h
+ tools/include/linux/compiler.h
+ tools/include/linux/compiler-gcc.h
+ tools/include/linux/coresight-pmu.h
++tools/include/linux/bug.h
+ tools/include/linux/filter.h
+ tools/include/linux/hash.h
+ tools/include/linux/kernel.h
diff --git a/objtool-4.9/tools-include-introduce-linux-compiler-gcc.h.patch b/objtool-4.9/tools-include-introduce-linux-compiler-gcc.h.patch
new file mode 100644 (file)
index 0000000..9c6c2f5
--- /dev/null
@@ -0,0 +1,84 @@
+From 192614010a5052fe92611c7076ef664fd9bb60e8 Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Fri, 10 Feb 2017 11:41:11 -0300
+Subject: tools include: Introduce linux/compiler-gcc.h
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit 192614010a5052fe92611c7076ef664fd9bb60e8 upstream.
+
+To match the kernel headers structure, setting up things that are
+specific to gcc or to some specific version of gcc.
+
+It gets included by linux/compiler.h when gcc is the compiler being
+used.
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Joe Perches <joe@perches.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-fabcqfq4asodq9t158hcs8t3@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/compiler-gcc.h |   14 ++++++++++++++
+ tools/include/linux/compiler.h     |   10 +++++-----
+ tools/perf/MANIFEST                |    1 +
+ 3 files changed, 20 insertions(+), 5 deletions(-)
+
+--- /dev/null
++++ b/tools/include/linux/compiler-gcc.h
+@@ -0,0 +1,14 @@
++#ifndef _TOOLS_LINUX_COMPILER_H_
++#error "Please don't include <linux/compiler-gcc.h> directly, include <linux/compiler.h> instead."
++#endif
++
++/*
++ * Common definitions for all gcc versions go here.
++ */
++#define GCC_VERSION (__GNUC__ * 10000         \
++                   + __GNUC_MINOR__ * 100     \
++                   + __GNUC_PATCHLEVEL__)
++
++#if GCC_VERSION >= 70000 && !defined(__CHECKER__)
++# define __fallthrough __attribute__ ((fallthrough))
++#endif
+--- a/tools/include/linux/compiler.h
++++ b/tools/include/linux/compiler.h
+@@ -1,6 +1,10 @@
+ #ifndef _TOOLS_LINUX_COMPILER_H_
+ #define _TOOLS_LINUX_COMPILER_H_
++#ifdef __GNUC__
++#include <linux/compiler-gcc.h>
++#endif
++
+ /* Optimization barrier */
+ /* The "volatile" is due to gcc bugs */
+ #define barrier() __asm__ __volatile__("": : :"memory")
+@@ -128,11 +132,7 @@ static __always_inline void __write_once
+ #ifndef __fallthrough
+-# if defined(__GNUC__) && __GNUC__ >= 7
+-#  define __fallthrough __attribute__ ((fallthrough))
+-# else
+-#  define __fallthrough
+-# endif
++# define __fallthrough
+ #endif
+ #endif /* _TOOLS_LINUX_COMPILER_H */
+--- a/tools/perf/MANIFEST
++++ b/tools/perf/MANIFEST
+@@ -61,6 +61,7 @@ tools/include/asm-generic/bitops.h
+ tools/include/linux/atomic.h
+ tools/include/linux/bitops.h
+ tools/include/linux/compiler.h
++tools/include/linux/compiler-gcc.h
+ tools/include/linux/coresight-pmu.h
+ tools/include/linux/filter.h
+ tools/include/linux/hash.h
diff --git a/objtool-4.9/tools-include-move-array_size-to-linux-kernel.h.patch b/objtool-4.9/tools-include-move-array_size-to-linux-kernel.h.patch
new file mode 100644 (file)
index 0000000..3190b0e
--- /dev/null
@@ -0,0 +1,56 @@
+From 8607c1ee734d12f62c6a46abef13a510e25a1839 Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Mon, 17 Apr 2017 11:29:26 -0300
+Subject: tools include: Move ARRAY_SIZE() to linux/kernel.h
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit 8607c1ee734d12f62c6a46abef13a510e25a1839 upstream.
+
+To match the kernel, then look for places redefining it to make it use
+this version, which checks that its parameter is an array at build time.
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-txlcf1im83bcbj6kh0wxmyy8@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/kernel.h |    3 +++
+ tools/perf/util/util.h       |    2 --
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+--- a/tools/include/linux/kernel.h
++++ b/tools/include/linux/kernel.h
+@@ -4,6 +4,7 @@
+ #include <stdarg.h>
+ #include <stddef.h>
+ #include <assert.h>
++#include <linux/compiler.h>
+ #ifndef UINT_MAX
+ #define UINT_MAX      (~0U)
+@@ -76,6 +77,8 @@
+ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+ int scnprintf(char * buf, size_t size, const char * fmt, ...);
++#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
++
+ /*
+  * This looks more complex than it should be. But we need to
+  * get the type for the ~ right in round_down (it needs to be
+--- a/tools/perf/util/util.h
++++ b/tools/perf/util/util.h
+@@ -23,8 +23,6 @@
+ #endif
+ #endif
+-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+-
+ #ifdef __GNUC__
+ #define TYPEOF(x) (__typeof__(x))
+ #else
diff --git a/objtool-4.9/tools-include-uapi-grab-copies-of-stat.h-and-fcntl.h.patch b/objtool-4.9/tools-include-uapi-grab-copies-of-stat.h-and-fcntl.h.patch
new file mode 100644 (file)
index 0000000..9938cca
--- /dev/null
@@ -0,0 +1,318 @@
+From 67ef28794d7e30f33936d655f2951e8dcae7cd5a Mon Sep 17 00:00:00 2001
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+Date: Thu, 30 Mar 2017 11:16:59 -0300
+Subject: tools include uapi: Grab copies of stat.h and fcntl.h
+
+From: Arnaldo Carvalho de Melo <acme@redhat.com>
+
+commit 67ef28794d7e30f33936d655f2951e8dcae7cd5a upstream.
+
+We will need it to build tools/perf/trace/beauty/statx.h.
+
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Jiri Olsa <jolsa@kernel.org>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-nin41ve2fa63lrfbdr6x57yr@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/linux/types.h      |    1 
+ tools/include/uapi/linux/fcntl.h |   72 +++++++++++++++
+ tools/include/uapi/linux/stat.h  |  176 +++++++++++++++++++++++++++++++++++++++
+ tools/perf/MANIFEST              |    2 
+ tools/perf/check-headers.sh      |    2 
+ 5 files changed, 253 insertions(+)
+
+--- a/tools/include/linux/types.h
++++ b/tools/include/linux/types.h
+@@ -7,6 +7,7 @@
+ #define __SANE_USERSPACE_TYPES__      /* For PPC64, to get LL64 types */
+ #include <asm/types.h>
++#include <asm/posix_types.h>
+ struct page;
+ struct kmem_cache;
+--- /dev/null
++++ b/tools/include/uapi/linux/fcntl.h
+@@ -0,0 +1,72 @@
++#ifndef _UAPI_LINUX_FCNTL_H
++#define _UAPI_LINUX_FCNTL_H
++
++#include <asm/fcntl.h>
++
++#define F_SETLEASE    (F_LINUX_SPECIFIC_BASE + 0)
++#define F_GETLEASE    (F_LINUX_SPECIFIC_BASE + 1)
++
++/*
++ * Cancel a blocking posix lock; internal use only until we expose an
++ * asynchronous lock api to userspace:
++ */
++#define F_CANCELLK    (F_LINUX_SPECIFIC_BASE + 5)
++
++/* Create a file descriptor with FD_CLOEXEC set. */
++#define F_DUPFD_CLOEXEC       (F_LINUX_SPECIFIC_BASE + 6)
++
++/*
++ * Request nofications on a directory.
++ * See below for events that may be notified.
++ */
++#define F_NOTIFY      (F_LINUX_SPECIFIC_BASE+2)
++
++/*
++ * Set and get of pipe page size array
++ */
++#define F_SETPIPE_SZ  (F_LINUX_SPECIFIC_BASE + 7)
++#define F_GETPIPE_SZ  (F_LINUX_SPECIFIC_BASE + 8)
++
++/*
++ * Set/Get seals
++ */
++#define F_ADD_SEALS   (F_LINUX_SPECIFIC_BASE + 9)
++#define F_GET_SEALS   (F_LINUX_SPECIFIC_BASE + 10)
++
++/*
++ * Types of seals
++ */
++#define F_SEAL_SEAL   0x0001  /* prevent further seals from being set */
++#define F_SEAL_SHRINK 0x0002  /* prevent file from shrinking */
++#define F_SEAL_GROW   0x0004  /* prevent file from growing */
++#define F_SEAL_WRITE  0x0008  /* prevent writes */
++/* (1U << 31) is reserved for signed error codes */
++
++/*
++ * Types of directory notifications that may be requested.
++ */
++#define DN_ACCESS     0x00000001      /* File accessed */
++#define DN_MODIFY     0x00000002      /* File modified */
++#define DN_CREATE     0x00000004      /* File created */
++#define DN_DELETE     0x00000008      /* File removed */
++#define DN_RENAME     0x00000010      /* File renamed */
++#define DN_ATTRIB     0x00000020      /* File changed attibutes */
++#define DN_MULTISHOT  0x80000000      /* Don't remove notifier */
++
++#define AT_FDCWD              -100    /* Special value used to indicate
++                                           openat should use the current
++                                           working directory. */
++#define AT_SYMLINK_NOFOLLOW   0x100   /* Do not follow symbolic links.  */
++#define AT_REMOVEDIR          0x200   /* Remove directory instead of
++                                           unlinking file.  */
++#define AT_SYMLINK_FOLLOW     0x400   /* Follow symbolic links.  */
++#define AT_NO_AUTOMOUNT               0x800   /* Suppress terminal automount traversal */
++#define AT_EMPTY_PATH         0x1000  /* Allow empty relative pathname */
++
++#define AT_STATX_SYNC_TYPE    0x6000  /* Type of synchronisation required from statx() */
++#define AT_STATX_SYNC_AS_STAT 0x0000  /* - Do whatever stat() does */
++#define AT_STATX_FORCE_SYNC   0x2000  /* - Force the attributes to be sync'd with the server */
++#define AT_STATX_DONT_SYNC    0x4000  /* - Don't sync attributes with the server */
++
++
++#endif /* _UAPI_LINUX_FCNTL_H */
+--- /dev/null
++++ b/tools/include/uapi/linux/stat.h
+@@ -0,0 +1,176 @@
++#ifndef _UAPI_LINUX_STAT_H
++#define _UAPI_LINUX_STAT_H
++
++#include <linux/types.h>
++
++#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
++
++#define S_IFMT  00170000
++#define S_IFSOCK 0140000
++#define S_IFLNK        0120000
++#define S_IFREG  0100000
++#define S_IFBLK  0060000
++#define S_IFDIR  0040000
++#define S_IFCHR  0020000
++#define S_IFIFO  0010000
++#define S_ISUID  0004000
++#define S_ISGID  0002000
++#define S_ISVTX  0001000
++
++#define S_ISLNK(m)    (((m) & S_IFMT) == S_IFLNK)
++#define S_ISREG(m)    (((m) & S_IFMT) == S_IFREG)
++#define S_ISDIR(m)    (((m) & S_IFMT) == S_IFDIR)
++#define S_ISCHR(m)    (((m) & S_IFMT) == S_IFCHR)
++#define S_ISBLK(m)    (((m) & S_IFMT) == S_IFBLK)
++#define S_ISFIFO(m)   (((m) & S_IFMT) == S_IFIFO)
++#define S_ISSOCK(m)   (((m) & S_IFMT) == S_IFSOCK)
++
++#define S_IRWXU 00700
++#define S_IRUSR 00400
++#define S_IWUSR 00200
++#define S_IXUSR 00100
++
++#define S_IRWXG 00070
++#define S_IRGRP 00040
++#define S_IWGRP 00020
++#define S_IXGRP 00010
++
++#define S_IRWXO 00007
++#define S_IROTH 00004
++#define S_IWOTH 00002
++#define S_IXOTH 00001
++
++#endif
++
++/*
++ * Timestamp structure for the timestamps in struct statx.
++ *
++ * tv_sec holds the number of seconds before (negative) or after (positive)
++ * 00:00:00 1st January 1970 UTC.
++ *
++ * tv_nsec holds a number of nanoseconds before (0..-999,999,999 if tv_sec is
++ * negative) or after (0..999,999,999 if tv_sec is positive) the tv_sec time.
++ *
++ * Note that if both tv_sec and tv_nsec are non-zero, then the two values must
++ * either be both positive or both negative.
++ *
++ * __reserved is held in case we need a yet finer resolution.
++ */
++struct statx_timestamp {
++      __s64   tv_sec;
++      __s32   tv_nsec;
++      __s32   __reserved;
++};
++
++/*
++ * Structures for the extended file attribute retrieval system call
++ * (statx()).
++ *
++ * The caller passes a mask of what they're specifically interested in as a
++ * parameter to statx().  What statx() actually got will be indicated in
++ * st_mask upon return.
++ *
++ * For each bit in the mask argument:
++ *
++ * - if the datum is not supported:
++ *
++ *   - the bit will be cleared, and
++ *
++ *   - the datum will be set to an appropriate fabricated value if one is
++ *     available (eg. CIFS can take a default uid and gid), otherwise
++ *
++ *   - the field will be cleared;
++ *
++ * - otherwise, if explicitly requested:
++ *
++ *   - the datum will be synchronised to the server if AT_STATX_FORCE_SYNC is
++ *     set or if the datum is considered out of date, and
++ *
++ *   - the field will be filled in and the bit will be set;
++ *
++ * - otherwise, if not requested, but available in approximate form without any
++ *   effort, it will be filled in anyway, and the bit will be set upon return
++ *   (it might not be up to date, however, and no attempt will be made to
++ *   synchronise the internal state first);
++ *
++ * - otherwise the field and the bit will be cleared before returning.
++ *
++ * Items in STATX_BASIC_STATS may be marked unavailable on return, but they
++ * will have values installed for compatibility purposes so that stat() and
++ * co. can be emulated in userspace.
++ */
++struct statx {
++      /* 0x00 */
++      __u32   stx_mask;       /* What results were written [uncond] */
++      __u32   stx_blksize;    /* Preferred general I/O size [uncond] */
++      __u64   stx_attributes; /* Flags conveying information about the file [uncond] */
++      /* 0x10 */
++      __u32   stx_nlink;      /* Number of hard links */
++      __u32   stx_uid;        /* User ID of owner */
++      __u32   stx_gid;        /* Group ID of owner */
++      __u16   stx_mode;       /* File mode */
++      __u16   __spare0[1];
++      /* 0x20 */
++      __u64   stx_ino;        /* Inode number */
++      __u64   stx_size;       /* File size */
++      __u64   stx_blocks;     /* Number of 512-byte blocks allocated */
++      __u64   __spare1[1];
++      /* 0x40 */
++      struct statx_timestamp  stx_atime;      /* Last access time */
++      struct statx_timestamp  stx_btime;      /* File creation time */
++      struct statx_timestamp  stx_ctime;      /* Last attribute change time */
++      struct statx_timestamp  stx_mtime;      /* Last data modification time */
++      /* 0x80 */
++      __u32   stx_rdev_major; /* Device ID of special file [if bdev/cdev] */
++      __u32   stx_rdev_minor;
++      __u32   stx_dev_major;  /* ID of device containing file [uncond] */
++      __u32   stx_dev_minor;
++      /* 0x90 */
++      __u64   __spare2[14];   /* Spare space for future expansion */
++      /* 0x100 */
++};
++
++/*
++ * Flags to be stx_mask
++ *
++ * Query request/result mask for statx() and struct statx::stx_mask.
++ *
++ * These bits should be set in the mask argument of statx() to request
++ * particular items when calling statx().
++ */
++#define STATX_TYPE            0x00000001U     /* Want/got stx_mode & S_IFMT */
++#define STATX_MODE            0x00000002U     /* Want/got stx_mode & ~S_IFMT */
++#define STATX_NLINK           0x00000004U     /* Want/got stx_nlink */
++#define STATX_UID             0x00000008U     /* Want/got stx_uid */
++#define STATX_GID             0x00000010U     /* Want/got stx_gid */
++#define STATX_ATIME           0x00000020U     /* Want/got stx_atime */
++#define STATX_MTIME           0x00000040U     /* Want/got stx_mtime */
++#define STATX_CTIME           0x00000080U     /* Want/got stx_ctime */
++#define STATX_INO             0x00000100U     /* Want/got stx_ino */
++#define STATX_SIZE            0x00000200U     /* Want/got stx_size */
++#define STATX_BLOCKS          0x00000400U     /* Want/got stx_blocks */
++#define STATX_BASIC_STATS     0x000007ffU     /* The stuff in the normal stat struct */
++#define STATX_BTIME           0x00000800U     /* Want/got stx_btime */
++#define STATX_ALL             0x00000fffU     /* All currently supported flags */
++
++/*
++ * Attributes to be found in stx_attributes
++ *
++ * These give information about the features or the state of a file that might
++ * be of use to ordinary userspace programs such as GUIs or ls rather than
++ * specialised tools.
++ *
++ * Note that the flags marked [I] correspond to generic FS_IOC_FLAGS
++ * semantically.  Where possible, the numerical value is picked to correspond
++ * also.
++ */
++#define STATX_ATTR_COMPRESSED         0x00000004 /* [I] File is compressed by the fs */
++#define STATX_ATTR_IMMUTABLE          0x00000010 /* [I] File is marked immutable */
++#define STATX_ATTR_APPEND             0x00000020 /* [I] File is append-only */
++#define STATX_ATTR_NODUMP             0x00000040 /* [I] File is not to be dumped */
++#define STATX_ATTR_ENCRYPTED          0x00000800 /* [I] File requires key to decrypt in fs */
++
++#define STATX_ATTR_AUTOMOUNT          0x00001000 /* Dir: Automount trigger */
++
++
++#endif /* _UAPI_LINUX_STAT_H */
+--- a/tools/perf/MANIFEST
++++ b/tools/perf/MANIFEST
+@@ -72,9 +72,11 @@ tools/include/uapi/asm-generic/mman-comm
+ tools/include/uapi/asm-generic/mman.h
+ tools/include/uapi/linux/bpf.h
+ tools/include/uapi/linux/bpf_common.h
++tools/include/uapi/linux/fcntl.h
+ tools/include/uapi/linux/hw_breakpoint.h
+ tools/include/uapi/linux/mman.h
+ tools/include/uapi/linux/perf_event.h
++tools/include/uapi/linux/stat.h
+ tools/include/linux/poison.h
+ tools/include/linux/rbtree.h
+ tools/include/linux/rbtree_augmented.h
+--- a/tools/perf/check-headers.sh
++++ b/tools/perf/check-headers.sh
+@@ -1,7 +1,9 @@
+ #!/bin/sh
+ HEADERS='
++include/uapi/linux/fcntl.h
+ include/uapi/linux/perf_event.h
++include/uapi/linux/stat.h
+ include/linux/hash.h
+ include/uapi/linux/hw_breakpoint.h
+ arch/x86/include/asm/disabled-features.h
diff --git a/objtool-4.9/tools-lib-add-for_each_clear_bit-macro.patch b/objtool-4.9/tools-lib-add-for_each_clear_bit-macro.patch
new file mode 100644 (file)
index 0000000..a7eb117
--- /dev/null
@@ -0,0 +1,153 @@
+From 02bc11de567273da8ab25c54336ddbb71986f38f Mon Sep 17 00:00:00 2001
+From: Jiri Olsa <jolsa@kernel.org>
+Date: Mon, 10 Oct 2016 09:26:33 +0200
+Subject: tools lib: Add for_each_clear_bit macro
+
+From: Jiri Olsa <jolsa@kernel.org>
+
+commit 02bc11de567273da8ab25c54336ddbb71986f38f upstream.
+
+Adding for_each_clear_bit macro plus all its the necessary backbone
+functions. Taken from related kernel code. It will be used in following
+patch.
+
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Cc: Adrian Hunter <adrian.hunter@intel.com>
+Cc: David Ahern <dsahern@gmail.com>
+Cc: Namhyung Kim <namhyung@kernel.org>
+Cc: Wang Nan <wangnan0@huawei.com>
+Link: http://lkml.kernel.org/n/tip-cayv2zbqi0nlmg5sjjxs1775@git.kernel.org
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/include/asm-generic/bitops.h       |    1 +
+ tools/include/asm-generic/bitops/__ffz.h |   12 ++++++++++++
+ tools/include/asm-generic/bitops/find.h  |   28 ++++++++++++++++++++++++++++
+ tools/include/linux/bitops.h             |    5 +++++
+ tools/lib/find_bit.c                     |   25 +++++++++++++++++++++++++
+ tools/perf/MANIFEST                      |    1 +
+ 6 files changed, 72 insertions(+)
+
+--- a/tools/include/asm-generic/bitops.h
++++ b/tools/include/asm-generic/bitops.h
+@@ -13,6 +13,7 @@
+  */
+ #include <asm-generic/bitops/__ffs.h>
++#include <asm-generic/bitops/__ffz.h>
+ #include <asm-generic/bitops/fls.h>
+ #include <asm-generic/bitops/__fls.h>
+ #include <asm-generic/bitops/fls64.h>
+--- /dev/null
++++ b/tools/include/asm-generic/bitops/__ffz.h
+@@ -0,0 +1,12 @@
++#ifndef _ASM_GENERIC_BITOPS_FFZ_H_
++#define _ASM_GENERIC_BITOPS_FFZ_H_
++
++/*
++ * ffz - find first zero in word.
++ * @word: The word to search
++ *
++ * Undefined if no zero exists, so code should check against ~0UL first.
++ */
++#define ffz(x)  __ffs(~(x))
++
++#endif /* _ASM_GENERIC_BITOPS_FFZ_H_ */
+--- a/tools/include/asm-generic/bitops/find.h
++++ b/tools/include/asm-generic/bitops/find.h
+@@ -15,6 +15,21 @@ extern unsigned long find_next_bit(const
+               size, unsigned long offset);
+ #endif
++#ifndef find_next_zero_bit
++
++/**
++ * find_next_zero_bit - find the next cleared bit in a memory region
++ * @addr: The address to base the search on
++ * @offset: The bitnumber to start searching at
++ * @size: The bitmap size in bits
++ *
++ * Returns the bit number of the next zero bit
++ * If no bits are zero, returns @size.
++ */
++unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
++                               unsigned long offset);
++#endif
++
+ #ifndef find_first_bit
+ /**
+@@ -30,4 +45,17 @@ extern unsigned long find_first_bit(cons
+ #endif /* find_first_bit */
++#ifndef find_first_zero_bit
++
++/**
++ * find_first_zero_bit - find the first cleared bit in a memory region
++ * @addr: The address to start the search at
++ * @size: The maximum number of bits to search
++ *
++ * Returns the bit number of the first cleared bit.
++ * If no bits are zero, returns @size.
++ */
++unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size);
++#endif
++
+ #endif /*_TOOLS_LINUX_ASM_GENERIC_BITOPS_FIND_H_ */
+--- a/tools/include/linux/bitops.h
++++ b/tools/include/linux/bitops.h
+@@ -39,6 +39,11 @@ extern unsigned long __sw_hweight64(__u6
+            (bit) < (size);                                    \
+            (bit) = find_next_bit((addr), (size), (bit) + 1))
++#define for_each_clear_bit(bit, addr, size) \
++      for ((bit) = find_first_zero_bit((addr), (size));       \
++           (bit) < (size);                                    \
++           (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
++
+ /* same as for_each_set_bit() but use bit as value to start with */
+ #define for_each_set_bit_from(bit, addr, size) \
+       for ((bit) = find_next_bit((addr), (size), (bit));      \
+--- a/tools/lib/find_bit.c
++++ b/tools/lib/find_bit.c
+@@ -82,3 +82,28 @@ unsigned long find_first_bit(const unsig
+       return size;
+ }
+ #endif
++
++#ifndef find_first_zero_bit
++/*
++ * Find the first cleared bit in a memory region.
++ */
++unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
++{
++      unsigned long idx;
++
++      for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
++              if (addr[idx] != ~0UL)
++                      return min(idx * BITS_PER_LONG + ffz(addr[idx]), size);
++      }
++
++      return size;
++}
++#endif
++
++#ifndef find_next_zero_bit
++unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
++                               unsigned long offset)
++{
++      return _find_next_bit(addr, size, offset, ~0UL);
++}
++#endif
+--- a/tools/perf/MANIFEST
++++ b/tools/perf/MANIFEST
+@@ -51,6 +51,7 @@ tools/include/asm-generic/bitops/arch_hw
+ tools/include/asm-generic/bitops/atomic.h
+ tools/include/asm-generic/bitops/const_hweight.h
+ tools/include/asm-generic/bitops/__ffs.h
++tools/include/asm-generic/bitops/__ffz.h
+ tools/include/asm-generic/bitops/__fls.h
+ tools/include/asm-generic/bitops/find.h
+ tools/include/asm-generic/bitops/fls64.h
diff --git a/objtool-4.9/xen-fixup.patch b/objtool-4.9/xen-fixup.patch
new file mode 100644 (file)
index 0000000..aa8e293
--- /dev/null
@@ -0,0 +1,46 @@
+From foo@baz Sun Jun  3 13:37:03 CEST 2018
+Date: Sun, 03 Jun 2018 13:37:03 +0200
+To: Greg KH <gregkh@linuxfoundation.org>
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Subject: x86/xen: Add unwind hint annotations to xen_setup_gdt
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+Not needed in mainline as this function got rewritten in 4.12
+
+This enables objtool to grok the iret in the middle of a C function.
+
+This matches commit 76846bf3cb09 ("x86/asm: Add unwind hint annotations
+to sync_core()")
+
+Cc: Josh Poimboeuf <jpoimboe@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/xen/enlighten.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/xen/enlighten.c
++++ b/arch/x86/xen/enlighten.c
+@@ -75,6 +75,7 @@
+ #include <asm/mwait.h>
+ #include <asm/pci_x86.h>
+ #include <asm/cpu.h>
++#include <asm/unwind_hints.h>
+ #ifdef CONFIG_ACPI
+ #include <linux/acpi.h>
+@@ -1458,10 +1459,12 @@ static void __ref xen_setup_gdt(int cpu)
+                * GDT. The new GDT has  __KERNEL_CS with CS.L = 1
+                * and we are jumping to reload it.
+                */
+-              asm volatile ("pushq %0\n"
++              asm volatile (UNWIND_HINT_SAVE
++                            "pushq %0\n"
+                             "leaq 1f(%%rip),%0\n"
+                             "pushq %0\n"
+                             "lretq\n"
++                            UNWIND_HINT_RESTORE
+                             "1:\n"
+                             : "=&r" (dummy) : "0" (__KERNEL_CS));
index 51eb2887f62785b691c5fa6a4e49fd66a026d94d..7a1523ea4d8e453d59d5f8cff6715842def5342c 100644 (file)
@@ -1,8 +1,6 @@
 arm64-lse-add-early-clobbers-to-some-input-output-asm-operands.patch
 powerpc-64s-clear-pcr-on-boot.patch
 usb-serial-cp210x-use-tcflag_t-to-fix-incompatible-pointer-type.patch
-objtool-improve-detection-of-bug-and-other-dead-ends.patch
-objtool-move-checking-code-to-check.c.patch
 revert-pinctrl-msm-use-dynamic-gpio-numbering.patch
 xfs-detect-agfl-count-corruption-and-reset-agfl.patch
 revert-ima-limit-file-hash-setting-by-user-to-fix-and-log-modes.patch