Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

objtool: Add tool to perform compile-time stack metadata validation

This adds a host tool named objtool which has a "check" subcommand which
analyzes .o files to ensure the validity of stack metadata. It enforces
a set of rules on asm code and C inline assembly code so that stack
traces can be reliable.

For each function, it recursively follows all possible code paths and
validates the correct frame pointer state at each instruction.

It also follows code paths involving kernel special sections, like
.altinstructions, __jump_table, and __ex_table, which can add
alternative execution paths to a given instruction (or set of
instructions). Similarly, it knows how to follow switch statements, for
which gcc sometimes uses jump tables.

Here are some of the benefits of validating stack metadata:

a) More reliable stack traces for frame pointer enabled kernels

Frame pointers are used for debugging purposes. They allow runtime
code and debug tools to be able to walk the stack to determine the
chain of function call sites that led to the currently executing
code.

For some architectures, frame pointers are enabled by
CONFIG_FRAME_POINTER. For some other architectures they may be
required by the ABI (sometimes referred to as "backchain pointers").

For C code, gcc automatically generates instructions for setting up
frame pointers when the -fno-omit-frame-pointer option is used.

But for asm code, the frame setup instructions have to be written by
hand, which most people don't do. So the end result is that
CONFIG_FRAME_POINTER is honored for C code but not for most asm code.

For stack traces based on frame pointers to be reliable, all
functions which call other functions must first create a stack frame
and update the frame pointer. If a first function doesn't properly
create a stack frame before calling a second function, the *caller*
of the first function will be skipped on the stack trace.

For example, consider the following example backtrace with frame
pointers enabled:

[<ffffffff81812584>] dump_stack+0x4b/0x63
[<ffffffff812d6dc2>] cmdline_proc_show+0x12/0x30
[<ffffffff8127f568>] seq_read+0x108/0x3e0
[<ffffffff812cce62>] proc_reg_read+0x42/0x70
[<ffffffff81256197>] __vfs_read+0x37/0x100
[<ffffffff81256b16>] vfs_read+0x86/0x130
[<ffffffff81257898>] SyS_read+0x58/0xd0
[<ffffffff8181c1f2>] entry_SYSCALL_64_fastpath+0x12/0x76

It correctly shows that the caller of cmdline_proc_show() is
seq_read().

If we remove the frame pointer logic from cmdline_proc_show() by
replacing the frame pointer related instructions with nops, here's
what it looks like instead:

[<ffffffff81812584>] dump_stack+0x4b/0x63
[<ffffffff812d6dc2>] cmdline_proc_show+0x12/0x30
[<ffffffff812cce62>] proc_reg_read+0x42/0x70
[<ffffffff81256197>] __vfs_read+0x37/0x100
[<ffffffff81256b16>] vfs_read+0x86/0x130
[<ffffffff81257898>] SyS_read+0x58/0xd0
[<ffffffff8181c1f2>] entry_SYSCALL_64_fastpath+0x12/0x76

Notice that cmdline_proc_show()'s caller, seq_read(), has been
skipped. Instead the stack trace seems to show that
cmdline_proc_show() was called by proc_reg_read().

The benefit of "objtool check" here is that because it ensures that
*all* functions honor CONFIG_FRAME_POINTER, no functions will ever[*]
be skipped on a stack trace.

[*] unless an interrupt or exception has occurred at the very
beginning of a function before the stack frame has been created,
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

This is not yet implemented. For more details about what is planned,
see tools/objtool/Documentation/stack-validation.txt.

c) Higher live patching compatibility rate

This is not yet implemented. For more details about what is planned,
see tools/objtool/Documentation/stack-validation.txt.

To achieve the validation, "objtool check" enforces the following rules:

1. Each callable function must be annotated as such with the ELF
function type. In asm code, this is typically done using the
ENTRY/ENDPROC macros. If objtool finds a return instruction
outside of a function, it flags an error since that usually indicates
callable code which should be annotated accordingly.

This rule is needed so that objtool can properly identify each
callable function in order to analyze its stack metadata.

2. Conversely, each section of code which is *not* callable should *not*
be annotated as an ELF function. The ENDPROC macro shouldn't be used
in this case.

This rule is needed so that objtool can ignore non-callable code.
Such code doesn't have to follow any of the other rules.

3. Each callable function which calls another function must have the
correct frame pointer logic, if required by CONFIG_FRAME_POINTER or
the architecture's back chain rules. This can by done in asm code
with the FRAME_BEGIN/FRAME_END macros.

This rule ensures that frame pointer based stack traces will work as
designed. If function A doesn't create a stack frame before calling
function B, the _caller_ of function A will be skipped on the stack
trace.

4. Dynamic jumps and jumps to undefined symbols are only allowed if:

a) the jump is part of a switch statement; or

b) the jump matches sibling call semantics and the frame pointer has
the same value it had on function entry.

This rule is needed so that objtool can reliably analyze all of a
function's code paths. If a function jumps to code in another file,
and it's not a sibling call, objtool has no way to follow the jump
because it only analyzes a single file at a time.

5. A callable function may not execute kernel entry/exit instructions.
The only code which needs such instructions is kernel entry code,
which shouldn't be be in callable functions anyway.

This rule is just a sanity check to ensure that callable functions
return normally.

It currently only supports x86_64. I tried to make the code generic so
that support for other architectures can hopefully be plugged in
relatively easily.

On my Lenovo laptop with a i7-4810MQ 4-core/8-thread CPU, building the
kernel with objtool checking every .o file adds about three seconds of
total build time. It hasn't been optimized for performance yet, so
there are probably some opportunities for better build performance.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Bernd Petrovitsch <bernd@petrovitsch.priv.at>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Chris J Arges <chris.j.arges@canonical.com>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Michal Marek <mmarek@suse.cz>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Pedro Alves <palves@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: live-patching@vger.kernel.org
Link: http://lkml.kernel.org/r/f3efb173de43bd067b060de73f856567c0fa1174.1456719558.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Josh Poimboeuf and committed by
Ingo Molnar
442f04c3 87aaff2a

+5178 -6
+5
MAINTAINERS
··· 7778 7778 S: Maintained 7779 7779 F: sound/soc/codecs/tfa9879* 7780 7780 7781 + OBJTOOL 7782 + M: Josh Poimboeuf <jpoimboe@redhat.com> 7783 + S: Supported 7784 + F: tools/objtool/ 7785 + 7781 7786 OMAP SUPPORT 7782 7787 M: Tony Lindgren <tony@atomide.com> 7783 7788 L: linux-omap@vger.kernel.org
+8 -6
tools/Makefile
··· 20 20 @echo ' perf - Linux performance measurement and analysis tool' 21 21 @echo ' selftests - various kernel selftests' 22 22 @echo ' spi - spi tools' 23 + @echo ' objtool - an ELF object analysis tool' 23 24 @echo ' tmon - thermal monitoring and tuning tool' 24 25 @echo ' turbostat - Intel CPU idle stats and freq reporting tool' 25 26 @echo ' usb - USB testing tools' ··· 54 53 cpupower: FORCE 55 54 $(call descend,power/$@) 56 55 57 - cgroup firewire hv guest spi usb virtio vm net iio: FORCE 56 + cgroup firewire hv guest spi usb virtio vm net iio objtool: FORCE 58 57 $(call descend,$@) 59 58 60 59 liblockdep: FORCE ··· 86 85 all: acpi cgroup cpupower hv firewire lguest \ 87 86 perf selftests turbostat usb \ 88 87 virtio vm net x86_energy_perf_policy \ 89 - tmon freefall 88 + tmon freefall objtool 90 89 91 90 acpi_install: 92 91 $(call descend,power/$(@:_install=),install) ··· 94 93 cpupower_install: 95 94 $(call descend,power/$(@:_install=),install) 96 95 97 - cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install: 96 + cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install: 98 97 $(call descend,$(@:_install=),install) 99 98 100 99 selftests_install: ··· 112 111 install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ 113 112 perf_install selftests_install turbostat_install usb_install \ 114 113 virtio_install vm_install net_install x86_energy_perf_policy_install \ 115 - tmon_install freefall_install 114 + tmon_install freefall_install objtool_install 116 115 117 116 acpi_clean: 118 117 $(call descend,power/acpi,clean) ··· 120 119 cpupower_clean: 121 120 $(call descend,power/cpupower,clean) 122 121 123 - cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean: 122 + cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean objtool_clean: 124 123 $(call descend,$(@:_clean=),clean) 125 124 126 125 liblockdep_clean: ··· 156 155 clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \ 157 156 perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ 158 157 vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ 159 - freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean 158 + freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \ 159 + objtool_clean 160 160 161 161 .PHONY: FORCE
+2
tools/objtool/.gitignore
··· 1 + arch/x86/insn/inat-tables.c 2 + objtool
+13
tools/objtool/Build
··· 1 + objtool-y += arch/$(ARCH)/ 2 + objtool-y += builtin-check.o 3 + objtool-y += elf.o 4 + objtool-y += special.o 5 + objtool-y += objtool.o 6 + 7 + objtool-y += libstring.o 8 + 9 + CFLAGS += -I$(srctree)/tools/lib 10 + 11 + $(OUTPUT)libstring.o: ../lib/string.c FORCE 12 + $(call rule_mkdir) 13 + $(call if_changed_dep,cc_o_c)
+342
tools/objtool/Documentation/stack-validation.txt
··· 1 + Compile-time stack metadata validation 2 + ====================================== 3 + 4 + 5 + Overview 6 + -------- 7 + 8 + The kernel CONFIG_STACK_VALIDATION option enables a host tool named 9 + objtool which runs at compile time. It has a "check" subcommand which 10 + analyzes every .o file and ensures the validity of its stack metadata. 11 + It enforces a set of rules on asm code and C inline assembly code so 12 + that stack traces can be reliable. 13 + 14 + Currently it only checks frame pointer usage, but there are plans to add 15 + CFI validation for C files and CFI generation for asm files. 16 + 17 + For each function, it recursively follows all possible code paths and 18 + validates the correct frame pointer state at each instruction. 19 + 20 + It also follows code paths involving special sections, like 21 + .altinstructions, __jump_table, and __ex_table, which can add 22 + alternative execution paths to a given instruction (or set of 23 + instructions). Similarly, it knows how to follow switch statements, for 24 + which gcc sometimes uses jump tables. 25 + 26 + 27 + Why do we need stack metadata validation? 28 + ----------------------------------------- 29 + 30 + Here are some of the benefits of validating stack metadata: 31 + 32 + a) More reliable stack traces for frame pointer enabled kernels 33 + 34 + Frame pointers are used for debugging purposes. They allow runtime 35 + code and debug tools to be able to walk the stack to determine the 36 + chain of function call sites that led to the currently executing 37 + code. 38 + 39 + For some architectures, frame pointers are enabled by 40 + CONFIG_FRAME_POINTER. For some other architectures they may be 41 + required by the ABI (sometimes referred to as "backchain pointers"). 42 + 43 + For C code, gcc automatically generates instructions for setting up 44 + frame pointers when the -fno-omit-frame-pointer option is used. 45 + 46 + But for asm code, the frame setup instructions have to be written by 47 + hand, which most people don't do. So the end result is that 48 + CONFIG_FRAME_POINTER is honored for C code but not for most asm code. 49 + 50 + For stack traces based on frame pointers to be reliable, all 51 + functions which call other functions must first create a stack frame 52 + and update the frame pointer. If a first function doesn't properly 53 + create a stack frame before calling a second function, the *caller* 54 + of the first function will be skipped on the stack trace. 55 + 56 + For example, consider the following example backtrace with frame 57 + pointers enabled: 58 + 59 + [<ffffffff81812584>] dump_stack+0x4b/0x63 60 + [<ffffffff812d6dc2>] cmdline_proc_show+0x12/0x30 61 + [<ffffffff8127f568>] seq_read+0x108/0x3e0 62 + [<ffffffff812cce62>] proc_reg_read+0x42/0x70 63 + [<ffffffff81256197>] __vfs_read+0x37/0x100 64 + [<ffffffff81256b16>] vfs_read+0x86/0x130 65 + [<ffffffff81257898>] SyS_read+0x58/0xd0 66 + [<ffffffff8181c1f2>] entry_SYSCALL_64_fastpath+0x12/0x76 67 + 68 + It correctly shows that the caller of cmdline_proc_show() is 69 + seq_read(). 70 + 71 + If we remove the frame pointer logic from cmdline_proc_show() by 72 + replacing the frame pointer related instructions with nops, here's 73 + what it looks like instead: 74 + 75 + [<ffffffff81812584>] dump_stack+0x4b/0x63 76 + [<ffffffff812d6dc2>] cmdline_proc_show+0x12/0x30 77 + [<ffffffff812cce62>] proc_reg_read+0x42/0x70 78 + [<ffffffff81256197>] __vfs_read+0x37/0x100 79 + [<ffffffff81256b16>] vfs_read+0x86/0x130 80 + [<ffffffff81257898>] SyS_read+0x58/0xd0 81 + [<ffffffff8181c1f2>] entry_SYSCALL_64_fastpath+0x12/0x76 82 + 83 + Notice that cmdline_proc_show()'s caller, seq_read(), has been 84 + skipped. Instead the stack trace seems to show that 85 + cmdline_proc_show() was called by proc_reg_read(). 86 + 87 + The benefit of objtool here is that because it ensures that *all* 88 + functions honor CONFIG_FRAME_POINTER, no functions will ever[*] be 89 + skipped on a stack trace. 90 + 91 + [*] unless an interrupt or exception has occurred at the very 92 + beginning of a function before the stack frame has been created, 93 + or at the very end of the function after the stack frame has been 94 + destroyed. This is an inherent limitation of frame pointers. 95 + 96 + b) 100% reliable stack traces for DWARF enabled kernels 97 + 98 + (NOTE: This is not yet implemented) 99 + 100 + As an alternative to frame pointers, DWARF Call Frame Information 101 + (CFI) metadata can be used to walk the stack. Unlike frame pointers, 102 + CFI metadata is out of band. So it doesn't affect runtime 103 + performance and it can be reliable even when interrupts or exceptions 104 + are involved. 105 + 106 + For C code, gcc automatically generates DWARF CFI metadata. But for 107 + asm code, generating CFI is a tedious manual approach which requires 108 + manually placed .cfi assembler macros to be scattered throughout the 109 + code. It's clumsy and very easy to get wrong, and it makes the real 110 + code harder to read. 111 + 112 + Stacktool will improve this situation in several ways. For code 113 + which already has CFI annotations, it will validate them. For code 114 + which doesn't have CFI annotations, it will generate them. So an 115 + architecture can opt to strip out all the manual .cfi annotations 116 + from their asm code and have objtool generate them instead. 117 + 118 + We might also add a runtime stack validation debug option where we 119 + periodically walk the stack from schedule() and/or an NMI to ensure 120 + that the stack metadata is sane and that we reach the bottom of the 121 + stack. 122 + 123 + So the benefit of objtool here will be that external tooling should 124 + always show perfect stack traces. And the same will be true for 125 + kernel warning/oops traces if the architecture has a runtime DWARF 126 + unwinder. 127 + 128 + c) Higher live patching compatibility rate 129 + 130 + (NOTE: This is not yet implemented) 131 + 132 + Currently with CONFIG_LIVEPATCH there's a basic live patching 133 + framework which is safe for roughly 85-90% of "security" fixes. But 134 + patches can't have complex features like function dependency or 135 + prototype changes, or data structure changes. 136 + 137 + There's a strong need to support patches which have the more complex 138 + features so that the patch compatibility rate for security fixes can 139 + eventually approach something resembling 100%. To achieve that, a 140 + "consistency model" is needed, which allows tasks to be safely 141 + transitioned from an unpatched state to a patched state. 142 + 143 + One of the key requirements of the currently proposed livepatch 144 + consistency model [*] is that it needs to walk the stack of each 145 + sleeping task to determine if it can be transitioned to the patched 146 + state. If objtool can ensure that stack traces are reliable, this 147 + consistency model can be used and the live patching compatibility 148 + rate can be improved significantly. 149 + 150 + [*] https://lkml.kernel.org/r/cover.1423499826.git.jpoimboe@redhat.com 151 + 152 + 153 + Rules 154 + ----- 155 + 156 + To achieve the validation, objtool enforces the following rules: 157 + 158 + 1. Each callable function must be annotated as such with the ELF 159 + function type. In asm code, this is typically done using the 160 + ENTRY/ENDPROC macros. If objtool finds a return instruction 161 + outside of a function, it flags an error since that usually indicates 162 + callable code which should be annotated accordingly. 163 + 164 + This rule is needed so that objtool can properly identify each 165 + callable function in order to analyze its stack metadata. 166 + 167 + 2. Conversely, each section of code which is *not* callable should *not* 168 + be annotated as an ELF function. The ENDPROC macro shouldn't be used 169 + in this case. 170 + 171 + This rule is needed so that objtool can ignore non-callable code. 172 + Such code doesn't have to follow any of the other rules. 173 + 174 + 3. Each callable function which calls another function must have the 175 + correct frame pointer logic, if required by CONFIG_FRAME_POINTER or 176 + the architecture's back chain rules. This can by done in asm code 177 + with the FRAME_BEGIN/FRAME_END macros. 178 + 179 + This rule ensures that frame pointer based stack traces will work as 180 + designed. If function A doesn't create a stack frame before calling 181 + function B, the _caller_ of function A will be skipped on the stack 182 + trace. 183 + 184 + 4. Dynamic jumps and jumps to undefined symbols are only allowed if: 185 + 186 + a) the jump is part of a switch statement; or 187 + 188 + b) the jump matches sibling call semantics and the frame pointer has 189 + the same value it had on function entry. 190 + 191 + This rule is needed so that objtool can reliably analyze all of a 192 + function's code paths. If a function jumps to code in another file, 193 + and it's not a sibling call, objtool has no way to follow the jump 194 + because it only analyzes a single file at a time. 195 + 196 + 5. A callable function may not execute kernel entry/exit instructions. 197 + The only code which needs such instructions is kernel entry code, 198 + which shouldn't be be in callable functions anyway. 199 + 200 + This rule is just a sanity check to ensure that callable functions 201 + return normally. 202 + 203 + 204 + Errors in .S files 205 + ------------------ 206 + 207 + If you're getting an error in a compiled .S file which you don't 208 + understand, first make sure that the affected code follows the above 209 + rules. 210 + 211 + Here are some examples of common warnings reported by objtool, what 212 + they mean, and suggestions for how to fix them. 213 + 214 + 215 + 1. asm_file.o: warning: objtool: func()+0x128: call without frame pointer save/setup 216 + 217 + The func() function made a function call without first saving and/or 218 + updating the frame pointer. 219 + 220 + If func() is indeed a callable function, add proper frame pointer 221 + logic using the FRAME_BEGIN and FRAME_END macros. Otherwise, remove 222 + its ELF function annotation by changing ENDPROC to END. 223 + 224 + If you're getting this error in a .c file, see the "Errors in .c 225 + files" section. 226 + 227 + 228 + 2. asm_file.o: warning: objtool: .text+0x53: return instruction outside of a callable function 229 + 230 + A return instruction was detected, but objtool couldn't find a way 231 + for a callable function to reach the instruction. 232 + 233 + If the return instruction is inside (or reachable from) a callable 234 + function, the function needs to be annotated with the ENTRY/ENDPROC 235 + macros. 236 + 237 + If you _really_ need a return instruction outside of a function, and 238 + are 100% sure that it won't affect stack traces, you can tell 239 + objtool to ignore it. See the "Adding exceptions" section below. 240 + 241 + 242 + 3. asm_file.o: warning: objtool: func()+0x9: function has unreachable instruction 243 + 244 + The instruction lives inside of a callable function, but there's no 245 + possible control flow path from the beginning of the function to the 246 + instruction. 247 + 248 + If the instruction is actually needed, and it's actually in a 249 + callable function, ensure that its function is properly annotated 250 + with ENTRY/ENDPROC. 251 + 252 + If it's not actually in a callable function (e.g. kernel entry code), 253 + change ENDPROC to END. 254 + 255 + 256 + 4. asm_file.o: warning: objtool: func(): can't find starting instruction 257 + or 258 + asm_file.o: warning: objtool: func()+0x11dd: can't decode instruction 259 + 260 + Did you put data in a text section? If so, that can confuse 261 + objtool's instruction decoder. Move the data to a more appropriate 262 + section like .data or .rodata. 263 + 264 + 265 + 5. asm_file.o: warning: objtool: func()+0x6: kernel entry/exit from callable instruction 266 + 267 + This is a kernel entry/exit instruction like sysenter or sysret. 268 + Such instructions aren't allowed in a callable function, and are most 269 + likely part of the kernel entry code. 270 + 271 + If the instruction isn't actually in a callable function, change 272 + ENDPROC to END. 273 + 274 + 275 + 6. asm_file.o: warning: objtool: func()+0x26: sibling call from callable instruction with changed frame pointer 276 + 277 + This is a dynamic jump or a jump to an undefined symbol. Stacktool 278 + assumed it's a sibling call and detected that the frame pointer 279 + wasn't first restored to its original state. 280 + 281 + If it's not really a sibling call, you may need to move the 282 + destination code to the local file. 283 + 284 + If the instruction is not actually in a callable function (e.g. 285 + kernel entry code), change ENDPROC to END. 286 + 287 + 288 + 7. asm_file: warning: objtool: func()+0x5c: frame pointer state mismatch 289 + 290 + The instruction's frame pointer state is inconsistent, depending on 291 + which execution path was taken to reach the instruction. 292 + 293 + Make sure the function pushes and sets up the frame pointer (for 294 + x86_64, this means rbp) at the beginning of the function and pops it 295 + at the end of the function. Also make sure that no other code in the 296 + function touches the frame pointer. 297 + 298 + 299 + Errors in .c files 300 + ------------------ 301 + 302 + If you're getting an objtool error in a compiled .c file, chances are 303 + the file uses an asm() statement which has a "call" instruction. An 304 + asm() statement with a call instruction must declare the use of the 305 + stack pointer in its output operand. For example, on x86_64: 306 + 307 + register void *__sp asm("rsp"); 308 + asm volatile("call func" : "+r" (__sp)); 309 + 310 + Otherwise the stack frame may not get created before the call. 311 + 312 + Another possible cause for errors in C code is if the Makefile removes 313 + -fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. 314 + 315 + Also see the above section for .S file errors for more information what 316 + the individual error messages mean. 317 + 318 + If the error doesn't seem to make sense, it could be a bug in objtool. 319 + Feel free to ask the objtool maintainer for help. 320 + 321 + 322 + Adding exceptions 323 + ----------------- 324 + 325 + If you _really_ need objtool to ignore something, and are 100% sure 326 + that it won't affect kernel stack traces, you can tell objtool to 327 + ignore it: 328 + 329 + - To skip validation of a function, use the STACK_FRAME_NON_STANDARD 330 + macro. 331 + 332 + - To skip validation of a file, add 333 + 334 + OBJECT_FILES_NON_STANDARD_filename.o := n 335 + 336 + to the Makefile. 337 + 338 + - To skip validation of a directory, add 339 + 340 + OBJECT_FILES_NON_STANDARD := y 341 + 342 + to the Makefile.
+60
tools/objtool/Makefile
··· 1 + include ../scripts/Makefile.include 2 + 3 + ifndef ($(ARCH)) 4 + ARCH ?= $(shell uname -m) 5 + ifeq ($(ARCH),x86_64) 6 + ARCH := x86 7 + endif 8 + endif 9 + 10 + ifeq ($(srctree),) 11 + srctree := $(patsubst %/,%,$(dir $(shell pwd))) 12 + srctree := $(patsubst %/,%,$(dir $(srctree))) 13 + endif 14 + 15 + SUBCMD_SRCDIR = $(srctree)/tools/lib/subcmd/ 16 + LIBSUBCMD = $(if $(OUTPUT),$(OUTPUT),$(SUBCMD_SRCDIR))libsubcmd.a 17 + 18 + OBJTOOL := $(OUTPUT)objtool 19 + OBJTOOL_IN := $(OBJTOOL)-in.o 20 + 21 + all: $(OBJTOOL) 22 + 23 + INCLUDES := -I$(srctree)/tools/include 24 + CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 $(INCLUDES) 25 + LDFLAGS += -lelf $(LIBSUBCMD) 26 + 27 + AWK = awk 28 + export srctree OUTPUT CFLAGS ARCH AWK 29 + include $(srctree)/tools/build/Makefile.include 30 + 31 + $(OBJTOOL_IN): fixdep FORCE 32 + @$(MAKE) $(build)=objtool 33 + 34 + $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) 35 + @(test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ 36 + diff -I'^#include' arch/x86/insn/insn.c ../../arch/x86/lib/insn.c >/dev/null && \ 37 + diff -I'^#include' arch/x86/insn/inat.c ../../arch/x86/lib/inat.c >/dev/null && \ 38 + diff arch/x86/insn/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null && \ 39 + diff arch/x86/insn/gen-insn-attr-x86.awk ../../arch/x86/tools/gen-insn-attr-x86.awk >/dev/null && \ 40 + diff -I'^#include' arch/x86/insn/insn.h ../../arch/x86/include/asm/insn.h >/dev/null && \ 41 + diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ 42 + diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ 43 + || echo "Warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true 44 + $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ 45 + 46 + 47 + $(LIBSUBCMD): fixdep FORCE 48 + $(Q)$(MAKE) -C $(SUBCMD_SRCDIR) 49 + 50 + $(LIBSUBCMD)-clean: 51 + $(Q)$(MAKE) -C $(SUBCMD_SRCDIR) clean > /dev/null 52 + 53 + clean: $(LIBSUBCMD)-clean 54 + $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL) 55 + $(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete 56 + $(Q)$(RM) $(OUTPUT)arch/x86/insn/inat-tables.c $(OUTPUT)fixdep 57 + 58 + FORCE: 59 + 60 + .PHONY: clean FORCE
+44
tools/objtool/arch.h
··· 1 + /* 2 + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 2 7 + * of the License, or (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #ifndef _ARCH_H 19 + #define _ARCH_H 20 + 21 + #include <stdbool.h> 22 + #include "elf.h" 23 + 24 + #define INSN_FP_SAVE 1 25 + #define INSN_FP_SETUP 2 26 + #define INSN_FP_RESTORE 3 27 + #define INSN_JUMP_CONDITIONAL 4 28 + #define INSN_JUMP_UNCONDITIONAL 5 29 + #define INSN_JUMP_DYNAMIC 6 30 + #define INSN_CALL 7 31 + #define INSN_CALL_DYNAMIC 8 32 + #define INSN_RETURN 9 33 + #define INSN_CONTEXT_SWITCH 10 34 + #define INSN_BUG 11 35 + #define INSN_NOP 12 36 + #define INSN_OTHER 13 37 + #define INSN_LAST INSN_OTHER 38 + 39 + int arch_decode_instruction(struct elf *elf, struct section *sec, 40 + unsigned long offset, unsigned int maxlen, 41 + unsigned int *len, unsigned char *type, 42 + unsigned long *displacement); 43 + 44 + #endif /* _ARCH_H */
+12
tools/objtool/arch/x86/Build
··· 1 + objtool-y += decode.o 2 + 3 + inat_tables_script = arch/x86/insn/gen-insn-attr-x86.awk 4 + inat_tables_maps = arch/x86/insn/x86-opcode-map.txt 5 + 6 + $(OUTPUT)arch/x86/insn/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) 7 + $(call rule_mkdir) 8 + $(Q)$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ 9 + 10 + $(OUTPUT)arch/x86/decode.o: $(OUTPUT)arch/x86/insn/inat-tables.c 11 + 12 + CFLAGS_decode.o += -I$(OUTPUT)arch/x86/insn
+172
tools/objtool/arch/x86/decode.c
··· 1 + /* 2 + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 2 7 + * of the License, or (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #include <stdio.h> 19 + #include <stdlib.h> 20 + 21 + #define unlikely(cond) (cond) 22 + #include "insn/insn.h" 23 + #include "insn/inat.c" 24 + #include "insn/insn.c" 25 + 26 + #include "../../elf.h" 27 + #include "../../arch.h" 28 + #include "../../warn.h" 29 + 30 + static int is_x86_64(struct elf *elf) 31 + { 32 + switch (elf->ehdr.e_machine) { 33 + case EM_X86_64: 34 + return 1; 35 + case EM_386: 36 + return 0; 37 + default: 38 + WARN("unexpected ELF machine type %d", elf->ehdr.e_machine); 39 + return -1; 40 + } 41 + } 42 + 43 + int arch_decode_instruction(struct elf *elf, struct section *sec, 44 + unsigned long offset, unsigned int maxlen, 45 + unsigned int *len, unsigned char *type, 46 + unsigned long *immediate) 47 + { 48 + struct insn insn; 49 + int x86_64; 50 + unsigned char op1, op2, ext; 51 + 52 + x86_64 = is_x86_64(elf); 53 + if (x86_64 == -1) 54 + return -1; 55 + 56 + insn_init(&insn, (void *)(sec->data + offset), maxlen, x86_64); 57 + insn_get_length(&insn); 58 + insn_get_opcode(&insn); 59 + insn_get_modrm(&insn); 60 + insn_get_immediate(&insn); 61 + 62 + if (!insn_complete(&insn)) { 63 + WARN_FUNC("can't decode instruction", sec, offset); 64 + return -1; 65 + } 66 + 67 + *len = insn.length; 68 + *type = INSN_OTHER; 69 + 70 + if (insn.vex_prefix.nbytes) 71 + return 0; 72 + 73 + op1 = insn.opcode.bytes[0]; 74 + op2 = insn.opcode.bytes[1]; 75 + 76 + switch (op1) { 77 + case 0x55: 78 + if (!insn.rex_prefix.nbytes) 79 + /* push rbp */ 80 + *type = INSN_FP_SAVE; 81 + break; 82 + 83 + case 0x5d: 84 + if (!insn.rex_prefix.nbytes) 85 + /* pop rbp */ 86 + *type = INSN_FP_RESTORE; 87 + break; 88 + 89 + case 0x70 ... 0x7f: 90 + *type = INSN_JUMP_CONDITIONAL; 91 + break; 92 + 93 + case 0x89: 94 + if (insn.rex_prefix.nbytes == 1 && 95 + insn.rex_prefix.bytes[0] == 0x48 && 96 + insn.modrm.nbytes && insn.modrm.bytes[0] == 0xe5) 97 + /* mov rsp, rbp */ 98 + *type = INSN_FP_SETUP; 99 + break; 100 + 101 + case 0x90: 102 + *type = INSN_NOP; 103 + break; 104 + 105 + case 0x0f: 106 + if (op2 >= 0x80 && op2 <= 0x8f) 107 + *type = INSN_JUMP_CONDITIONAL; 108 + else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || 109 + op2 == 0x35) 110 + /* sysenter, sysret */ 111 + *type = INSN_CONTEXT_SWITCH; 112 + else if (op2 == 0x0b || op2 == 0xb9) 113 + /* ud2 */ 114 + *type = INSN_BUG; 115 + else if (op2 == 0x0d || op2 == 0x1f) 116 + /* nopl/nopw */ 117 + *type = INSN_NOP; 118 + else if (op2 == 0x01 && insn.modrm.nbytes && 119 + (insn.modrm.bytes[0] == 0xc2 || 120 + insn.modrm.bytes[0] == 0xd8)) 121 + /* vmlaunch, vmrun */ 122 + *type = INSN_CONTEXT_SWITCH; 123 + 124 + break; 125 + 126 + case 0xc9: /* leave */ 127 + *type = INSN_FP_RESTORE; 128 + break; 129 + 130 + case 0xe3: /* jecxz/jrcxz */ 131 + *type = INSN_JUMP_CONDITIONAL; 132 + break; 133 + 134 + case 0xe9: 135 + case 0xeb: 136 + *type = INSN_JUMP_UNCONDITIONAL; 137 + break; 138 + 139 + case 0xc2: 140 + case 0xc3: 141 + *type = INSN_RETURN; 142 + break; 143 + 144 + case 0xc5: /* iret */ 145 + case 0xca: /* retf */ 146 + case 0xcb: /* retf */ 147 + *type = INSN_CONTEXT_SWITCH; 148 + break; 149 + 150 + case 0xe8: 151 + *type = INSN_CALL; 152 + break; 153 + 154 + case 0xff: 155 + ext = X86_MODRM_REG(insn.modrm.bytes[0]); 156 + if (ext == 2 || ext == 3) 157 + *type = INSN_CALL_DYNAMIC; 158 + else if (ext == 4) 159 + *type = INSN_JUMP_DYNAMIC; 160 + else if (ext == 5) /*jmpf */ 161 + *type = INSN_CONTEXT_SWITCH; 162 + 163 + break; 164 + 165 + default: 166 + break; 167 + } 168 + 169 + *immediate = insn.immediate.nbytes ? insn.immediate.value : 0; 170 + 171 + return 0; 172 + }
+387
tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk
··· 1 + #!/bin/awk -f 2 + # gen-insn-attr-x86.awk: Instruction attribute table generator 3 + # Written by Masami Hiramatsu <mhiramat@redhat.com> 4 + # 5 + # Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c 6 + 7 + # Awk implementation sanity check 8 + function check_awk_implement() { 9 + if (sprintf("%x", 0) != "0") 10 + return "Your awk has a printf-format problem." 11 + return "" 12 + } 13 + 14 + # Clear working vars 15 + function clear_vars() { 16 + delete table 17 + delete lptable2 18 + delete lptable1 19 + delete lptable3 20 + eid = -1 # escape id 21 + gid = -1 # group id 22 + aid = -1 # AVX id 23 + tname = "" 24 + } 25 + 26 + BEGIN { 27 + # Implementation error checking 28 + awkchecked = check_awk_implement() 29 + if (awkchecked != "") { 30 + print "Error: " awkchecked > "/dev/stderr" 31 + print "Please try to use gawk." > "/dev/stderr" 32 + exit 1 33 + } 34 + 35 + # Setup generating tables 36 + print "/* x86 opcode map generated from x86-opcode-map.txt */" 37 + print "/* Do not change this code. */\n" 38 + ggid = 1 39 + geid = 1 40 + gaid = 0 41 + delete etable 42 + delete gtable 43 + delete atable 44 + 45 + opnd_expr = "^[A-Za-z/]" 46 + ext_expr = "^\\(" 47 + sep_expr = "^\\|$" 48 + group_expr = "^Grp[0-9A-Za-z]+" 49 + 50 + imm_expr = "^[IJAOL][a-z]" 51 + imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" 52 + imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" 53 + imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" 54 + imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" 55 + imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" 56 + imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" 57 + imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" 58 + imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" 59 + imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" 60 + imm_flag["Ob"] = "INAT_MOFFSET" 61 + imm_flag["Ov"] = "INAT_MOFFSET" 62 + imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" 63 + 64 + modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" 65 + force64_expr = "\\([df]64\\)" 66 + rex_expr = "^REX(\\.[XRWB]+)*" 67 + fpu_expr = "^ESC" # TODO 68 + 69 + lprefix1_expr = "\\((66|!F3)\\)" 70 + lprefix2_expr = "\\(F3\\)" 71 + lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)" 72 + lprefix_expr = "\\((66|F2|F3)\\)" 73 + max_lprefix = 4 74 + 75 + # All opcodes starting with lower-case 'v' or with (v1) superscript 76 + # accepts VEX prefix 77 + vexok_opcode_expr = "^v.*" 78 + vexok_expr = "\\(v1\\)" 79 + # All opcodes with (v) superscript supports *only* VEX prefix 80 + vexonly_expr = "\\(v\\)" 81 + 82 + prefix_expr = "\\(Prefix\\)" 83 + prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" 84 + prefix_num["REPNE"] = "INAT_PFX_REPNE" 85 + prefix_num["REP/REPE"] = "INAT_PFX_REPE" 86 + prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" 87 + prefix_num["XRELEASE"] = "INAT_PFX_REPE" 88 + prefix_num["LOCK"] = "INAT_PFX_LOCK" 89 + prefix_num["SEG=CS"] = "INAT_PFX_CS" 90 + prefix_num["SEG=DS"] = "INAT_PFX_DS" 91 + prefix_num["SEG=ES"] = "INAT_PFX_ES" 92 + prefix_num["SEG=FS"] = "INAT_PFX_FS" 93 + prefix_num["SEG=GS"] = "INAT_PFX_GS" 94 + prefix_num["SEG=SS"] = "INAT_PFX_SS" 95 + prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" 96 + prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" 97 + prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" 98 + 99 + clear_vars() 100 + } 101 + 102 + function semantic_error(msg) { 103 + print "Semantic error at " NR ": " msg > "/dev/stderr" 104 + exit 1 105 + } 106 + 107 + function debug(msg) { 108 + print "DEBUG: " msg 109 + } 110 + 111 + function array_size(arr, i,c) { 112 + c = 0 113 + for (i in arr) 114 + c++ 115 + return c 116 + } 117 + 118 + /^Table:/ { 119 + print "/* " $0 " */" 120 + if (tname != "") 121 + semantic_error("Hit Table: before EndTable:."); 122 + } 123 + 124 + /^Referrer:/ { 125 + if (NF != 1) { 126 + # escape opcode table 127 + ref = "" 128 + for (i = 2; i <= NF; i++) 129 + ref = ref $i 130 + eid = escape[ref] 131 + tname = sprintf("inat_escape_table_%d", eid) 132 + } 133 + } 134 + 135 + /^AVXcode:/ { 136 + if (NF != 1) { 137 + # AVX/escape opcode table 138 + aid = $2 139 + if (gaid <= aid) 140 + gaid = aid + 1 141 + if (tname == "") # AVX only opcode table 142 + tname = sprintf("inat_avx_table_%d", $2) 143 + } 144 + if (aid == -1 && eid == -1) # primary opcode table 145 + tname = "inat_primary_table" 146 + } 147 + 148 + /^GrpTable:/ { 149 + print "/* " $0 " */" 150 + if (!($2 in group)) 151 + semantic_error("No group: " $2 ) 152 + gid = group[$2] 153 + tname = "inat_group_table_" gid 154 + } 155 + 156 + function print_table(tbl,name,fmt,n) 157 + { 158 + print "const insn_attr_t " name " = {" 159 + for (i = 0; i < n; i++) { 160 + id = sprintf(fmt, i) 161 + if (tbl[id]) 162 + print " [" id "] = " tbl[id] "," 163 + } 164 + print "};" 165 + } 166 + 167 + /^EndTable/ { 168 + if (gid != -1) { 169 + # print group tables 170 + if (array_size(table) != 0) { 171 + print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", 172 + "0x%x", 8) 173 + gtable[gid,0] = tname 174 + } 175 + if (array_size(lptable1) != 0) { 176 + print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", 177 + "0x%x", 8) 178 + gtable[gid,1] = tname "_1" 179 + } 180 + if (array_size(lptable2) != 0) { 181 + print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", 182 + "0x%x", 8) 183 + gtable[gid,2] = tname "_2" 184 + } 185 + if (array_size(lptable3) != 0) { 186 + print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", 187 + "0x%x", 8) 188 + gtable[gid,3] = tname "_3" 189 + } 190 + } else { 191 + # print primary/escaped tables 192 + if (array_size(table) != 0) { 193 + print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", 194 + "0x%02x", 256) 195 + etable[eid,0] = tname 196 + if (aid >= 0) 197 + atable[aid,0] = tname 198 + } 199 + if (array_size(lptable1) != 0) { 200 + print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", 201 + "0x%02x", 256) 202 + etable[eid,1] = tname "_1" 203 + if (aid >= 0) 204 + atable[aid,1] = tname "_1" 205 + } 206 + if (array_size(lptable2) != 0) { 207 + print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", 208 + "0x%02x", 256) 209 + etable[eid,2] = tname "_2" 210 + if (aid >= 0) 211 + atable[aid,2] = tname "_2" 212 + } 213 + if (array_size(lptable3) != 0) { 214 + print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", 215 + "0x%02x", 256) 216 + etable[eid,3] = tname "_3" 217 + if (aid >= 0) 218 + atable[aid,3] = tname "_3" 219 + } 220 + } 221 + print "" 222 + clear_vars() 223 + } 224 + 225 + function add_flags(old,new) { 226 + if (old && new) 227 + return old " | " new 228 + else if (old) 229 + return old 230 + else 231 + return new 232 + } 233 + 234 + # convert operands to flags. 235 + function convert_operands(count,opnd, i,j,imm,mod) 236 + { 237 + imm = null 238 + mod = null 239 + for (j = 1; j <= count; j++) { 240 + i = opnd[j] 241 + if (match(i, imm_expr) == 1) { 242 + if (!imm_flag[i]) 243 + semantic_error("Unknown imm opnd: " i) 244 + if (imm) { 245 + if (i != "Ib") 246 + semantic_error("Second IMM error") 247 + imm = add_flags(imm, "INAT_SCNDIMM") 248 + } else 249 + imm = imm_flag[i] 250 + } else if (match(i, modrm_expr)) 251 + mod = "INAT_MODRM" 252 + } 253 + return add_flags(imm, mod) 254 + } 255 + 256 + /^[0-9a-f]+\:/ { 257 + if (NR == 1) 258 + next 259 + # get index 260 + idx = "0x" substr($1, 1, index($1,":") - 1) 261 + if (idx in table) 262 + semantic_error("Redefine " idx " in " tname) 263 + 264 + # check if escaped opcode 265 + if ("escape" == $2) { 266 + if ($3 != "#") 267 + semantic_error("No escaped name") 268 + ref = "" 269 + for (i = 4; i <= NF; i++) 270 + ref = ref $i 271 + if (ref in escape) 272 + semantic_error("Redefine escape (" ref ")") 273 + escape[ref] = geid 274 + geid++ 275 + table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" 276 + next 277 + } 278 + 279 + variant = null 280 + # converts 281 + i = 2 282 + while (i <= NF) { 283 + opcode = $(i++) 284 + delete opnds 285 + ext = null 286 + flags = null 287 + opnd = null 288 + # parse one opcode 289 + if (match($i, opnd_expr)) { 290 + opnd = $i 291 + count = split($(i++), opnds, ",") 292 + flags = convert_operands(count, opnds) 293 + } 294 + if (match($i, ext_expr)) 295 + ext = $(i++) 296 + if (match($i, sep_expr)) 297 + i++ 298 + else if (i < NF) 299 + semantic_error($i " is not a separator") 300 + 301 + # check if group opcode 302 + if (match(opcode, group_expr)) { 303 + if (!(opcode in group)) { 304 + group[opcode] = ggid 305 + ggid++ 306 + } 307 + flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") 308 + } 309 + # check force(or default) 64bit 310 + if (match(ext, force64_expr)) 311 + flags = add_flags(flags, "INAT_FORCE64") 312 + 313 + # check REX prefix 314 + if (match(opcode, rex_expr)) 315 + flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") 316 + 317 + # check coprocessor escape : TODO 318 + if (match(opcode, fpu_expr)) 319 + flags = add_flags(flags, "INAT_MODRM") 320 + 321 + # check VEX codes 322 + if (match(ext, vexonly_expr)) 323 + flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") 324 + else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) 325 + flags = add_flags(flags, "INAT_VEXOK") 326 + 327 + # check prefixes 328 + if (match(ext, prefix_expr)) { 329 + if (!prefix_num[opcode]) 330 + semantic_error("Unknown prefix: " opcode) 331 + flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") 332 + } 333 + if (length(flags) == 0) 334 + continue 335 + # check if last prefix 336 + if (match(ext, lprefix1_expr)) { 337 + lptable1[idx] = add_flags(lptable1[idx],flags) 338 + variant = "INAT_VARIANT" 339 + } 340 + if (match(ext, lprefix2_expr)) { 341 + lptable2[idx] = add_flags(lptable2[idx],flags) 342 + variant = "INAT_VARIANT" 343 + } 344 + if (match(ext, lprefix3_expr)) { 345 + lptable3[idx] = add_flags(lptable3[idx],flags) 346 + variant = "INAT_VARIANT" 347 + } 348 + if (!match(ext, lprefix_expr)){ 349 + table[idx] = add_flags(table[idx],flags) 350 + } 351 + } 352 + if (variant) 353 + table[idx] = add_flags(table[idx],variant) 354 + } 355 + 356 + END { 357 + if (awkchecked != "") 358 + exit 1 359 + # print escape opcode map's array 360 + print "/* Escape opcode map array */" 361 + print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ 362 + "[INAT_LSTPFX_MAX + 1] = {" 363 + for (i = 0; i < geid; i++) 364 + for (j = 0; j < max_lprefix; j++) 365 + if (etable[i,j]) 366 + print " ["i"]["j"] = "etable[i,j]"," 367 + print "};\n" 368 + # print group opcode map's array 369 + print "/* Group opcode map array */" 370 + print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ 371 + "[INAT_LSTPFX_MAX + 1] = {" 372 + for (i = 0; i < ggid; i++) 373 + for (j = 0; j < max_lprefix; j++) 374 + if (gtable[i,j]) 375 + print " ["i"]["j"] = "gtable[i,j]"," 376 + print "};\n" 377 + # print AVX opcode map's array 378 + print "/* AVX opcode map array */" 379 + print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ 380 + "[INAT_LSTPFX_MAX + 1] = {" 381 + for (i = 0; i < gaid; i++) 382 + for (j = 0; j < max_lprefix; j++) 383 + if (atable[i,j]) 384 + print " ["i"]["j"] = "atable[i,j]"," 385 + print "};" 386 + } 387 +
+97
tools/objtool/arch/x86/insn/inat.c
··· 1 + /* 2 + * x86 instruction attribute tables 3 + * 4 + * Written by Masami Hiramatsu <mhiramat@redhat.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 + * 20 + */ 21 + #include "insn.h" 22 + 23 + /* Attribute tables are generated from opcode map */ 24 + #include "inat-tables.c" 25 + 26 + /* Attribute search APIs */ 27 + insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) 28 + { 29 + return inat_primary_table[opcode]; 30 + } 31 + 32 + int inat_get_last_prefix_id(insn_byte_t last_pfx) 33 + { 34 + insn_attr_t lpfx_attr; 35 + 36 + lpfx_attr = inat_get_opcode_attribute(last_pfx); 37 + return inat_last_prefix_id(lpfx_attr); 38 + } 39 + 40 + insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, 41 + insn_attr_t esc_attr) 42 + { 43 + const insn_attr_t *table; 44 + int n; 45 + 46 + n = inat_escape_id(esc_attr); 47 + 48 + table = inat_escape_tables[n][0]; 49 + if (!table) 50 + return 0; 51 + if (inat_has_variant(table[opcode]) && lpfx_id) { 52 + table = inat_escape_tables[n][lpfx_id]; 53 + if (!table) 54 + return 0; 55 + } 56 + return table[opcode]; 57 + } 58 + 59 + insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, 60 + insn_attr_t grp_attr) 61 + { 62 + const insn_attr_t *table; 63 + int n; 64 + 65 + n = inat_group_id(grp_attr); 66 + 67 + table = inat_group_tables[n][0]; 68 + if (!table) 69 + return inat_group_common_attribute(grp_attr); 70 + if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { 71 + table = inat_group_tables[n][lpfx_id]; 72 + if (!table) 73 + return inat_group_common_attribute(grp_attr); 74 + } 75 + return table[X86_MODRM_REG(modrm)] | 76 + inat_group_common_attribute(grp_attr); 77 + } 78 + 79 + insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, 80 + insn_byte_t vex_p) 81 + { 82 + const insn_attr_t *table; 83 + if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) 84 + return 0; 85 + /* At first, this checks the master table */ 86 + table = inat_avx_tables[vex_m][0]; 87 + if (!table) 88 + return 0; 89 + if (!inat_is_group(table[opcode]) && vex_p) { 90 + /* If this is not a group, get attribute directly */ 91 + table = inat_avx_tables[vex_m][vex_p]; 92 + if (!table) 93 + return 0; 94 + } 95 + return table[opcode]; 96 + } 97 +
+221
tools/objtool/arch/x86/insn/inat.h
··· 1 + #ifndef _ASM_X86_INAT_H 2 + #define _ASM_X86_INAT_H 3 + /* 4 + * x86 instruction attributes 5 + * 6 + * Written by Masami Hiramatsu <mhiramat@redhat.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2 of the License, or 11 + * (at your option) any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 + * 22 + */ 23 + #include "inat_types.h" 24 + 25 + /* 26 + * Internal bits. Don't use bitmasks directly, because these bits are 27 + * unstable. You should use checking functions. 28 + */ 29 + 30 + #define INAT_OPCODE_TABLE_SIZE 256 31 + #define INAT_GROUP_TABLE_SIZE 8 32 + 33 + /* Legacy last prefixes */ 34 + #define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ 35 + #define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ 36 + #define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ 37 + /* Other Legacy prefixes */ 38 + #define INAT_PFX_LOCK 4 /* 0xF0 */ 39 + #define INAT_PFX_CS 5 /* 0x2E */ 40 + #define INAT_PFX_DS 6 /* 0x3E */ 41 + #define INAT_PFX_ES 7 /* 0x26 */ 42 + #define INAT_PFX_FS 8 /* 0x64 */ 43 + #define INAT_PFX_GS 9 /* 0x65 */ 44 + #define INAT_PFX_SS 10 /* 0x36 */ 45 + #define INAT_PFX_ADDRSZ 11 /* 0x67 */ 46 + /* x86-64 REX prefix */ 47 + #define INAT_PFX_REX 12 /* 0x4X */ 48 + /* AVX VEX prefixes */ 49 + #define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ 50 + #define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ 51 + 52 + #define INAT_LSTPFX_MAX 3 53 + #define INAT_LGCPFX_MAX 11 54 + 55 + /* Immediate size */ 56 + #define INAT_IMM_BYTE 1 57 + #define INAT_IMM_WORD 2 58 + #define INAT_IMM_DWORD 3 59 + #define INAT_IMM_QWORD 4 60 + #define INAT_IMM_PTR 5 61 + #define INAT_IMM_VWORD32 6 62 + #define INAT_IMM_VWORD 7 63 + 64 + /* Legacy prefix */ 65 + #define INAT_PFX_OFFS 0 66 + #define INAT_PFX_BITS 4 67 + #define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) 68 + #define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) 69 + /* Escape opcodes */ 70 + #define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) 71 + #define INAT_ESC_BITS 2 72 + #define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) 73 + #define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) 74 + /* Group opcodes (1-16) */ 75 + #define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) 76 + #define INAT_GRP_BITS 5 77 + #define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) 78 + #define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) 79 + /* Immediates */ 80 + #define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) 81 + #define INAT_IMM_BITS 3 82 + #define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) 83 + /* Flags */ 84 + #define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) 85 + #define INAT_MODRM (1 << (INAT_FLAG_OFFS)) 86 + #define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) 87 + #define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) 88 + #define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) 89 + #define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) 90 + #define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) 91 + #define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) 92 + /* Attribute making macros for attribute tables */ 93 + #define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) 94 + #define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) 95 + #define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) 96 + #define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) 97 + 98 + /* Attribute search APIs */ 99 + extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); 100 + extern int inat_get_last_prefix_id(insn_byte_t last_pfx); 101 + extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, 102 + int lpfx_id, 103 + insn_attr_t esc_attr); 104 + extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, 105 + int lpfx_id, 106 + insn_attr_t esc_attr); 107 + extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, 108 + insn_byte_t vex_m, 109 + insn_byte_t vex_pp); 110 + 111 + /* Attribute checking functions */ 112 + static inline int inat_is_legacy_prefix(insn_attr_t attr) 113 + { 114 + attr &= INAT_PFX_MASK; 115 + return attr && attr <= INAT_LGCPFX_MAX; 116 + } 117 + 118 + static inline int inat_is_address_size_prefix(insn_attr_t attr) 119 + { 120 + return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; 121 + } 122 + 123 + static inline int inat_is_operand_size_prefix(insn_attr_t attr) 124 + { 125 + return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; 126 + } 127 + 128 + static inline int inat_is_rex_prefix(insn_attr_t attr) 129 + { 130 + return (attr & INAT_PFX_MASK) == INAT_PFX_REX; 131 + } 132 + 133 + static inline int inat_last_prefix_id(insn_attr_t attr) 134 + { 135 + if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) 136 + return 0; 137 + else 138 + return attr & INAT_PFX_MASK; 139 + } 140 + 141 + static inline int inat_is_vex_prefix(insn_attr_t attr) 142 + { 143 + attr &= INAT_PFX_MASK; 144 + return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3; 145 + } 146 + 147 + static inline int inat_is_vex3_prefix(insn_attr_t attr) 148 + { 149 + return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; 150 + } 151 + 152 + static inline int inat_is_escape(insn_attr_t attr) 153 + { 154 + return attr & INAT_ESC_MASK; 155 + } 156 + 157 + static inline int inat_escape_id(insn_attr_t attr) 158 + { 159 + return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; 160 + } 161 + 162 + static inline int inat_is_group(insn_attr_t attr) 163 + { 164 + return attr & INAT_GRP_MASK; 165 + } 166 + 167 + static inline int inat_group_id(insn_attr_t attr) 168 + { 169 + return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; 170 + } 171 + 172 + static inline int inat_group_common_attribute(insn_attr_t attr) 173 + { 174 + return attr & ~INAT_GRP_MASK; 175 + } 176 + 177 + static inline int inat_has_immediate(insn_attr_t attr) 178 + { 179 + return attr & INAT_IMM_MASK; 180 + } 181 + 182 + static inline int inat_immediate_size(insn_attr_t attr) 183 + { 184 + return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; 185 + } 186 + 187 + static inline int inat_has_modrm(insn_attr_t attr) 188 + { 189 + return attr & INAT_MODRM; 190 + } 191 + 192 + static inline int inat_is_force64(insn_attr_t attr) 193 + { 194 + return attr & INAT_FORCE64; 195 + } 196 + 197 + static inline int inat_has_second_immediate(insn_attr_t attr) 198 + { 199 + return attr & INAT_SCNDIMM; 200 + } 201 + 202 + static inline int inat_has_moffset(insn_attr_t attr) 203 + { 204 + return attr & INAT_MOFFSET; 205 + } 206 + 207 + static inline int inat_has_variant(insn_attr_t attr) 208 + { 209 + return attr & INAT_VARIANT; 210 + } 211 + 212 + static inline int inat_accept_vex(insn_attr_t attr) 213 + { 214 + return attr & INAT_VEXOK; 215 + } 216 + 217 + static inline int inat_must_vex(insn_attr_t attr) 218 + { 219 + return attr & INAT_VEXONLY; 220 + } 221 + #endif
+29
tools/objtool/arch/x86/insn/inat_types.h
··· 1 + #ifndef _ASM_X86_INAT_TYPES_H 2 + #define _ASM_X86_INAT_TYPES_H 3 + /* 4 + * x86 instruction attributes 5 + * 6 + * Written by Masami Hiramatsu <mhiramat@redhat.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2 of the License, or 11 + * (at your option) any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, write to the Free Software 20 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 + * 22 + */ 23 + 24 + /* Instruction attributes */ 25 + typedef unsigned int insn_attr_t; 26 + typedef unsigned char insn_byte_t; 27 + typedef signed int insn_value_t; 28 + 29 + #endif
+594
tools/objtool/arch/x86/insn/insn.c
··· 1 + /* 2 + * x86 instruction analysis 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License as published by 6 + * the Free Software Foundation; either version 2 of the License, or 7 + * (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, write to the Free Software 16 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 + * 18 + * Copyright (C) IBM Corporation, 2002, 2004, 2009 19 + */ 20 + 21 + #ifdef __KERNEL__ 22 + #include <linux/string.h> 23 + #else 24 + #include <string.h> 25 + #endif 26 + #include "inat.h" 27 + #include "insn.h" 28 + 29 + /* Verify next sizeof(t) bytes can be on the same instruction */ 30 + #define validate_next(t, insn, n) \ 31 + ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) 32 + 33 + #define __get_next(t, insn) \ 34 + ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) 35 + 36 + #define __peek_nbyte_next(t, insn, n) \ 37 + ({ t r = *(t*)((insn)->next_byte + n); r; }) 38 + 39 + #define get_next(t, insn) \ 40 + ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) 41 + 42 + #define peek_nbyte_next(t, insn, n) \ 43 + ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) 44 + 45 + #define peek_next(t, insn) peek_nbyte_next(t, insn, 0) 46 + 47 + /** 48 + * insn_init() - initialize struct insn 49 + * @insn: &struct insn to be initialized 50 + * @kaddr: address (in kernel memory) of instruction (or copy thereof) 51 + * @x86_64: !0 for 64-bit kernel or 64-bit app 52 + */ 53 + void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) 54 + { 55 + /* 56 + * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid 57 + * even if the input buffer is long enough to hold them. 58 + */ 59 + if (buf_len > MAX_INSN_SIZE) 60 + buf_len = MAX_INSN_SIZE; 61 + 62 + memset(insn, 0, sizeof(*insn)); 63 + insn->kaddr = kaddr; 64 + insn->end_kaddr = kaddr + buf_len; 65 + insn->next_byte = kaddr; 66 + insn->x86_64 = x86_64 ? 1 : 0; 67 + insn->opnd_bytes = 4; 68 + if (x86_64) 69 + insn->addr_bytes = 8; 70 + else 71 + insn->addr_bytes = 4; 72 + } 73 + 74 + /** 75 + * insn_get_prefixes - scan x86 instruction prefix bytes 76 + * @insn: &struct insn containing instruction 77 + * 78 + * Populates the @insn->prefixes bitmap, and updates @insn->next_byte 79 + * to point to the (first) opcode. No effect if @insn->prefixes.got 80 + * is already set. 81 + */ 82 + void insn_get_prefixes(struct insn *insn) 83 + { 84 + struct insn_field *prefixes = &insn->prefixes; 85 + insn_attr_t attr; 86 + insn_byte_t b, lb; 87 + int i, nb; 88 + 89 + if (prefixes->got) 90 + return; 91 + 92 + nb = 0; 93 + lb = 0; 94 + b = peek_next(insn_byte_t, insn); 95 + attr = inat_get_opcode_attribute(b); 96 + while (inat_is_legacy_prefix(attr)) { 97 + /* Skip if same prefix */ 98 + for (i = 0; i < nb; i++) 99 + if (prefixes->bytes[i] == b) 100 + goto found; 101 + if (nb == 4) 102 + /* Invalid instruction */ 103 + break; 104 + prefixes->bytes[nb++] = b; 105 + if (inat_is_address_size_prefix(attr)) { 106 + /* address size switches 2/4 or 4/8 */ 107 + if (insn->x86_64) 108 + insn->addr_bytes ^= 12; 109 + else 110 + insn->addr_bytes ^= 6; 111 + } else if (inat_is_operand_size_prefix(attr)) { 112 + /* oprand size switches 2/4 */ 113 + insn->opnd_bytes ^= 6; 114 + } 115 + found: 116 + prefixes->nbytes++; 117 + insn->next_byte++; 118 + lb = b; 119 + b = peek_next(insn_byte_t, insn); 120 + attr = inat_get_opcode_attribute(b); 121 + } 122 + /* Set the last prefix */ 123 + if (lb && lb != insn->prefixes.bytes[3]) { 124 + if (unlikely(insn->prefixes.bytes[3])) { 125 + /* Swap the last prefix */ 126 + b = insn->prefixes.bytes[3]; 127 + for (i = 0; i < nb; i++) 128 + if (prefixes->bytes[i] == lb) 129 + prefixes->bytes[i] = b; 130 + } 131 + insn->prefixes.bytes[3] = lb; 132 + } 133 + 134 + /* Decode REX prefix */ 135 + if (insn->x86_64) { 136 + b = peek_next(insn_byte_t, insn); 137 + attr = inat_get_opcode_attribute(b); 138 + if (inat_is_rex_prefix(attr)) { 139 + insn->rex_prefix.value = b; 140 + insn->rex_prefix.nbytes = 1; 141 + insn->next_byte++; 142 + if (X86_REX_W(b)) 143 + /* REX.W overrides opnd_size */ 144 + insn->opnd_bytes = 8; 145 + } 146 + } 147 + insn->rex_prefix.got = 1; 148 + 149 + /* Decode VEX prefix */ 150 + b = peek_next(insn_byte_t, insn); 151 + attr = inat_get_opcode_attribute(b); 152 + if (inat_is_vex_prefix(attr)) { 153 + insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); 154 + if (!insn->x86_64) { 155 + /* 156 + * In 32-bits mode, if the [7:6] bits (mod bits of 157 + * ModRM) on the second byte are not 11b, it is 158 + * LDS or LES. 159 + */ 160 + if (X86_MODRM_MOD(b2) != 3) 161 + goto vex_end; 162 + } 163 + insn->vex_prefix.bytes[0] = b; 164 + insn->vex_prefix.bytes[1] = b2; 165 + if (inat_is_vex3_prefix(attr)) { 166 + b2 = peek_nbyte_next(insn_byte_t, insn, 2); 167 + insn->vex_prefix.bytes[2] = b2; 168 + insn->vex_prefix.nbytes = 3; 169 + insn->next_byte += 3; 170 + if (insn->x86_64 && X86_VEX_W(b2)) 171 + /* VEX.W overrides opnd_size */ 172 + insn->opnd_bytes = 8; 173 + } else { 174 + /* 175 + * For VEX2, fake VEX3-like byte#2. 176 + * Makes it easier to decode vex.W, vex.vvvv, 177 + * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. 178 + */ 179 + insn->vex_prefix.bytes[2] = b2 & 0x7f; 180 + insn->vex_prefix.nbytes = 2; 181 + insn->next_byte += 2; 182 + } 183 + } 184 + vex_end: 185 + insn->vex_prefix.got = 1; 186 + 187 + prefixes->got = 1; 188 + 189 + err_out: 190 + return; 191 + } 192 + 193 + /** 194 + * insn_get_opcode - collect opcode(s) 195 + * @insn: &struct insn containing instruction 196 + * 197 + * Populates @insn->opcode, updates @insn->next_byte to point past the 198 + * opcode byte(s), and set @insn->attr (except for groups). 199 + * If necessary, first collects any preceding (prefix) bytes. 200 + * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got 201 + * is already 1. 202 + */ 203 + void insn_get_opcode(struct insn *insn) 204 + { 205 + struct insn_field *opcode = &insn->opcode; 206 + insn_byte_t op; 207 + int pfx_id; 208 + if (opcode->got) 209 + return; 210 + if (!insn->prefixes.got) 211 + insn_get_prefixes(insn); 212 + 213 + /* Get first opcode */ 214 + op = get_next(insn_byte_t, insn); 215 + opcode->bytes[0] = op; 216 + opcode->nbytes = 1; 217 + 218 + /* Check if there is VEX prefix or not */ 219 + if (insn_is_avx(insn)) { 220 + insn_byte_t m, p; 221 + m = insn_vex_m_bits(insn); 222 + p = insn_vex_p_bits(insn); 223 + insn->attr = inat_get_avx_attribute(op, m, p); 224 + if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr)) 225 + insn->attr = 0; /* This instruction is bad */ 226 + goto end; /* VEX has only 1 byte for opcode */ 227 + } 228 + 229 + insn->attr = inat_get_opcode_attribute(op); 230 + while (inat_is_escape(insn->attr)) { 231 + /* Get escaped opcode */ 232 + op = get_next(insn_byte_t, insn); 233 + opcode->bytes[opcode->nbytes++] = op; 234 + pfx_id = insn_last_prefix_id(insn); 235 + insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); 236 + } 237 + if (inat_must_vex(insn->attr)) 238 + insn->attr = 0; /* This instruction is bad */ 239 + end: 240 + opcode->got = 1; 241 + 242 + err_out: 243 + return; 244 + } 245 + 246 + /** 247 + * insn_get_modrm - collect ModRM byte, if any 248 + * @insn: &struct insn containing instruction 249 + * 250 + * Populates @insn->modrm and updates @insn->next_byte to point past the 251 + * ModRM byte, if any. If necessary, first collects the preceding bytes 252 + * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. 253 + */ 254 + void insn_get_modrm(struct insn *insn) 255 + { 256 + struct insn_field *modrm = &insn->modrm; 257 + insn_byte_t pfx_id, mod; 258 + if (modrm->got) 259 + return; 260 + if (!insn->opcode.got) 261 + insn_get_opcode(insn); 262 + 263 + if (inat_has_modrm(insn->attr)) { 264 + mod = get_next(insn_byte_t, insn); 265 + modrm->value = mod; 266 + modrm->nbytes = 1; 267 + if (inat_is_group(insn->attr)) { 268 + pfx_id = insn_last_prefix_id(insn); 269 + insn->attr = inat_get_group_attribute(mod, pfx_id, 270 + insn->attr); 271 + if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) 272 + insn->attr = 0; /* This is bad */ 273 + } 274 + } 275 + 276 + if (insn->x86_64 && inat_is_force64(insn->attr)) 277 + insn->opnd_bytes = 8; 278 + modrm->got = 1; 279 + 280 + err_out: 281 + return; 282 + } 283 + 284 + 285 + /** 286 + * insn_rip_relative() - Does instruction use RIP-relative addressing mode? 287 + * @insn: &struct insn containing instruction 288 + * 289 + * If necessary, first collects the instruction up to and including the 290 + * ModRM byte. No effect if @insn->x86_64 is 0. 291 + */ 292 + int insn_rip_relative(struct insn *insn) 293 + { 294 + struct insn_field *modrm = &insn->modrm; 295 + 296 + if (!insn->x86_64) 297 + return 0; 298 + if (!modrm->got) 299 + insn_get_modrm(insn); 300 + /* 301 + * For rip-relative instructions, the mod field (top 2 bits) 302 + * is zero and the r/m field (bottom 3 bits) is 0x5. 303 + */ 304 + return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); 305 + } 306 + 307 + /** 308 + * insn_get_sib() - Get the SIB byte of instruction 309 + * @insn: &struct insn containing instruction 310 + * 311 + * If necessary, first collects the instruction up to and including the 312 + * ModRM byte. 313 + */ 314 + void insn_get_sib(struct insn *insn) 315 + { 316 + insn_byte_t modrm; 317 + 318 + if (insn->sib.got) 319 + return; 320 + if (!insn->modrm.got) 321 + insn_get_modrm(insn); 322 + if (insn->modrm.nbytes) { 323 + modrm = (insn_byte_t)insn->modrm.value; 324 + if (insn->addr_bytes != 2 && 325 + X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { 326 + insn->sib.value = get_next(insn_byte_t, insn); 327 + insn->sib.nbytes = 1; 328 + } 329 + } 330 + insn->sib.got = 1; 331 + 332 + err_out: 333 + return; 334 + } 335 + 336 + 337 + /** 338 + * insn_get_displacement() - Get the displacement of instruction 339 + * @insn: &struct insn containing instruction 340 + * 341 + * If necessary, first collects the instruction up to and including the 342 + * SIB byte. 343 + * Displacement value is sign-expanded. 344 + */ 345 + void insn_get_displacement(struct insn *insn) 346 + { 347 + insn_byte_t mod, rm, base; 348 + 349 + if (insn->displacement.got) 350 + return; 351 + if (!insn->sib.got) 352 + insn_get_sib(insn); 353 + if (insn->modrm.nbytes) { 354 + /* 355 + * Interpreting the modrm byte: 356 + * mod = 00 - no displacement fields (exceptions below) 357 + * mod = 01 - 1-byte displacement field 358 + * mod = 10 - displacement field is 4 bytes, or 2 bytes if 359 + * address size = 2 (0x67 prefix in 32-bit mode) 360 + * mod = 11 - no memory operand 361 + * 362 + * If address size = 2... 363 + * mod = 00, r/m = 110 - displacement field is 2 bytes 364 + * 365 + * If address size != 2... 366 + * mod != 11, r/m = 100 - SIB byte exists 367 + * mod = 00, SIB base = 101 - displacement field is 4 bytes 368 + * mod = 00, r/m = 101 - rip-relative addressing, displacement 369 + * field is 4 bytes 370 + */ 371 + mod = X86_MODRM_MOD(insn->modrm.value); 372 + rm = X86_MODRM_RM(insn->modrm.value); 373 + base = X86_SIB_BASE(insn->sib.value); 374 + if (mod == 3) 375 + goto out; 376 + if (mod == 1) { 377 + insn->displacement.value = get_next(char, insn); 378 + insn->displacement.nbytes = 1; 379 + } else if (insn->addr_bytes == 2) { 380 + if ((mod == 0 && rm == 6) || mod == 2) { 381 + insn->displacement.value = 382 + get_next(short, insn); 383 + insn->displacement.nbytes = 2; 384 + } 385 + } else { 386 + if ((mod == 0 && rm == 5) || mod == 2 || 387 + (mod == 0 && base == 5)) { 388 + insn->displacement.value = get_next(int, insn); 389 + insn->displacement.nbytes = 4; 390 + } 391 + } 392 + } 393 + out: 394 + insn->displacement.got = 1; 395 + 396 + err_out: 397 + return; 398 + } 399 + 400 + /* Decode moffset16/32/64. Return 0 if failed */ 401 + static int __get_moffset(struct insn *insn) 402 + { 403 + switch (insn->addr_bytes) { 404 + case 2: 405 + insn->moffset1.value = get_next(short, insn); 406 + insn->moffset1.nbytes = 2; 407 + break; 408 + case 4: 409 + insn->moffset1.value = get_next(int, insn); 410 + insn->moffset1.nbytes = 4; 411 + break; 412 + case 8: 413 + insn->moffset1.value = get_next(int, insn); 414 + insn->moffset1.nbytes = 4; 415 + insn->moffset2.value = get_next(int, insn); 416 + insn->moffset2.nbytes = 4; 417 + break; 418 + default: /* opnd_bytes must be modified manually */ 419 + goto err_out; 420 + } 421 + insn->moffset1.got = insn->moffset2.got = 1; 422 + 423 + return 1; 424 + 425 + err_out: 426 + return 0; 427 + } 428 + 429 + /* Decode imm v32(Iz). Return 0 if failed */ 430 + static int __get_immv32(struct insn *insn) 431 + { 432 + switch (insn->opnd_bytes) { 433 + case 2: 434 + insn->immediate.value = get_next(short, insn); 435 + insn->immediate.nbytes = 2; 436 + break; 437 + case 4: 438 + case 8: 439 + insn->immediate.value = get_next(int, insn); 440 + insn->immediate.nbytes = 4; 441 + break; 442 + default: /* opnd_bytes must be modified manually */ 443 + goto err_out; 444 + } 445 + 446 + return 1; 447 + 448 + err_out: 449 + return 0; 450 + } 451 + 452 + /* Decode imm v64(Iv/Ov), Return 0 if failed */ 453 + static int __get_immv(struct insn *insn) 454 + { 455 + switch (insn->opnd_bytes) { 456 + case 2: 457 + insn->immediate1.value = get_next(short, insn); 458 + insn->immediate1.nbytes = 2; 459 + break; 460 + case 4: 461 + insn->immediate1.value = get_next(int, insn); 462 + insn->immediate1.nbytes = 4; 463 + break; 464 + case 8: 465 + insn->immediate1.value = get_next(int, insn); 466 + insn->immediate1.nbytes = 4; 467 + insn->immediate2.value = get_next(int, insn); 468 + insn->immediate2.nbytes = 4; 469 + break; 470 + default: /* opnd_bytes must be modified manually */ 471 + goto err_out; 472 + } 473 + insn->immediate1.got = insn->immediate2.got = 1; 474 + 475 + return 1; 476 + err_out: 477 + return 0; 478 + } 479 + 480 + /* Decode ptr16:16/32(Ap) */ 481 + static int __get_immptr(struct insn *insn) 482 + { 483 + switch (insn->opnd_bytes) { 484 + case 2: 485 + insn->immediate1.value = get_next(short, insn); 486 + insn->immediate1.nbytes = 2; 487 + break; 488 + case 4: 489 + insn->immediate1.value = get_next(int, insn); 490 + insn->immediate1.nbytes = 4; 491 + break; 492 + case 8: 493 + /* ptr16:64 is not exist (no segment) */ 494 + return 0; 495 + default: /* opnd_bytes must be modified manually */ 496 + goto err_out; 497 + } 498 + insn->immediate2.value = get_next(unsigned short, insn); 499 + insn->immediate2.nbytes = 2; 500 + insn->immediate1.got = insn->immediate2.got = 1; 501 + 502 + return 1; 503 + err_out: 504 + return 0; 505 + } 506 + 507 + /** 508 + * insn_get_immediate() - Get the immediates of instruction 509 + * @insn: &struct insn containing instruction 510 + * 511 + * If necessary, first collects the instruction up to and including the 512 + * displacement bytes. 513 + * Basically, most of immediates are sign-expanded. Unsigned-value can be 514 + * get by bit masking with ((1 << (nbytes * 8)) - 1) 515 + */ 516 + void insn_get_immediate(struct insn *insn) 517 + { 518 + if (insn->immediate.got) 519 + return; 520 + if (!insn->displacement.got) 521 + insn_get_displacement(insn); 522 + 523 + if (inat_has_moffset(insn->attr)) { 524 + if (!__get_moffset(insn)) 525 + goto err_out; 526 + goto done; 527 + } 528 + 529 + if (!inat_has_immediate(insn->attr)) 530 + /* no immediates */ 531 + goto done; 532 + 533 + switch (inat_immediate_size(insn->attr)) { 534 + case INAT_IMM_BYTE: 535 + insn->immediate.value = get_next(char, insn); 536 + insn->immediate.nbytes = 1; 537 + break; 538 + case INAT_IMM_WORD: 539 + insn->immediate.value = get_next(short, insn); 540 + insn->immediate.nbytes = 2; 541 + break; 542 + case INAT_IMM_DWORD: 543 + insn->immediate.value = get_next(int, insn); 544 + insn->immediate.nbytes = 4; 545 + break; 546 + case INAT_IMM_QWORD: 547 + insn->immediate1.value = get_next(int, insn); 548 + insn->immediate1.nbytes = 4; 549 + insn->immediate2.value = get_next(int, insn); 550 + insn->immediate2.nbytes = 4; 551 + break; 552 + case INAT_IMM_PTR: 553 + if (!__get_immptr(insn)) 554 + goto err_out; 555 + break; 556 + case INAT_IMM_VWORD32: 557 + if (!__get_immv32(insn)) 558 + goto err_out; 559 + break; 560 + case INAT_IMM_VWORD: 561 + if (!__get_immv(insn)) 562 + goto err_out; 563 + break; 564 + default: 565 + /* Here, insn must have an immediate, but failed */ 566 + goto err_out; 567 + } 568 + if (inat_has_second_immediate(insn->attr)) { 569 + insn->immediate2.value = get_next(char, insn); 570 + insn->immediate2.nbytes = 1; 571 + } 572 + done: 573 + insn->immediate.got = 1; 574 + 575 + err_out: 576 + return; 577 + } 578 + 579 + /** 580 + * insn_get_length() - Get the length of instruction 581 + * @insn: &struct insn containing instruction 582 + * 583 + * If necessary, first collects the instruction up to and including the 584 + * immediates bytes. 585 + */ 586 + void insn_get_length(struct insn *insn) 587 + { 588 + if (insn->length) 589 + return; 590 + if (!insn->immediate.got) 591 + insn_get_immediate(insn); 592 + insn->length = (unsigned char)((unsigned long)insn->next_byte 593 + - (unsigned long)insn->kaddr); 594 + }
+201
tools/objtool/arch/x86/insn/insn.h
··· 1 + #ifndef _ASM_X86_INSN_H 2 + #define _ASM_X86_INSN_H 3 + /* 4 + * x86 instruction analysis 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 + * 20 + * Copyright (C) IBM Corporation, 2009 21 + */ 22 + 23 + /* insn_attr_t is defined in inat.h */ 24 + #include "inat.h" 25 + 26 + struct insn_field { 27 + union { 28 + insn_value_t value; 29 + insn_byte_t bytes[4]; 30 + }; 31 + /* !0 if we've run insn_get_xxx() for this field */ 32 + unsigned char got; 33 + unsigned char nbytes; 34 + }; 35 + 36 + struct insn { 37 + struct insn_field prefixes; /* 38 + * Prefixes 39 + * prefixes.bytes[3]: last prefix 40 + */ 41 + struct insn_field rex_prefix; /* REX prefix */ 42 + struct insn_field vex_prefix; /* VEX prefix */ 43 + struct insn_field opcode; /* 44 + * opcode.bytes[0]: opcode1 45 + * opcode.bytes[1]: opcode2 46 + * opcode.bytes[2]: opcode3 47 + */ 48 + struct insn_field modrm; 49 + struct insn_field sib; 50 + struct insn_field displacement; 51 + union { 52 + struct insn_field immediate; 53 + struct insn_field moffset1; /* for 64bit MOV */ 54 + struct insn_field immediate1; /* for 64bit imm or off16/32 */ 55 + }; 56 + union { 57 + struct insn_field moffset2; /* for 64bit MOV */ 58 + struct insn_field immediate2; /* for 64bit imm or seg16 */ 59 + }; 60 + 61 + insn_attr_t attr; 62 + unsigned char opnd_bytes; 63 + unsigned char addr_bytes; 64 + unsigned char length; 65 + unsigned char x86_64; 66 + 67 + const insn_byte_t *kaddr; /* kernel address of insn to analyze */ 68 + const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ 69 + const insn_byte_t *next_byte; 70 + }; 71 + 72 + #define MAX_INSN_SIZE 15 73 + 74 + #define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) 75 + #define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) 76 + #define X86_MODRM_RM(modrm) ((modrm) & 0x07) 77 + 78 + #define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) 79 + #define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) 80 + #define X86_SIB_BASE(sib) ((sib) & 0x07) 81 + 82 + #define X86_REX_W(rex) ((rex) & 8) 83 + #define X86_REX_R(rex) ((rex) & 4) 84 + #define X86_REX_X(rex) ((rex) & 2) 85 + #define X86_REX_B(rex) ((rex) & 1) 86 + 87 + /* VEX bit flags */ 88 + #define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ 89 + #define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ 90 + #define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ 91 + #define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ 92 + #define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ 93 + /* VEX bit fields */ 94 + #define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ 95 + #define X86_VEX2_M 1 /* VEX2.M always 1 */ 96 + #define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ 97 + #define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ 98 + #define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ 99 + 100 + extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); 101 + extern void insn_get_prefixes(struct insn *insn); 102 + extern void insn_get_opcode(struct insn *insn); 103 + extern void insn_get_modrm(struct insn *insn); 104 + extern void insn_get_sib(struct insn *insn); 105 + extern void insn_get_displacement(struct insn *insn); 106 + extern void insn_get_immediate(struct insn *insn); 107 + extern void insn_get_length(struct insn *insn); 108 + 109 + /* Attribute will be determined after getting ModRM (for opcode groups) */ 110 + static inline void insn_get_attribute(struct insn *insn) 111 + { 112 + insn_get_modrm(insn); 113 + } 114 + 115 + /* Instruction uses RIP-relative addressing */ 116 + extern int insn_rip_relative(struct insn *insn); 117 + 118 + /* Init insn for kernel text */ 119 + static inline void kernel_insn_init(struct insn *insn, 120 + const void *kaddr, int buf_len) 121 + { 122 + #ifdef CONFIG_X86_64 123 + insn_init(insn, kaddr, buf_len, 1); 124 + #else /* CONFIG_X86_32 */ 125 + insn_init(insn, kaddr, buf_len, 0); 126 + #endif 127 + } 128 + 129 + static inline int insn_is_avx(struct insn *insn) 130 + { 131 + if (!insn->prefixes.got) 132 + insn_get_prefixes(insn); 133 + return (insn->vex_prefix.value != 0); 134 + } 135 + 136 + /* Ensure this instruction is decoded completely */ 137 + static inline int insn_complete(struct insn *insn) 138 + { 139 + return insn->opcode.got && insn->modrm.got && insn->sib.got && 140 + insn->displacement.got && insn->immediate.got; 141 + } 142 + 143 + static inline insn_byte_t insn_vex_m_bits(struct insn *insn) 144 + { 145 + if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ 146 + return X86_VEX2_M; 147 + else 148 + return X86_VEX3_M(insn->vex_prefix.bytes[1]); 149 + } 150 + 151 + static inline insn_byte_t insn_vex_p_bits(struct insn *insn) 152 + { 153 + if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ 154 + return X86_VEX_P(insn->vex_prefix.bytes[1]); 155 + else 156 + return X86_VEX_P(insn->vex_prefix.bytes[2]); 157 + } 158 + 159 + /* Get the last prefix id from last prefix or VEX prefix */ 160 + static inline int insn_last_prefix_id(struct insn *insn) 161 + { 162 + if (insn_is_avx(insn)) 163 + return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ 164 + 165 + if (insn->prefixes.bytes[3]) 166 + return inat_get_last_prefix_id(insn->prefixes.bytes[3]); 167 + 168 + return 0; 169 + } 170 + 171 + /* Offset of each field from kaddr */ 172 + static inline int insn_offset_rex_prefix(struct insn *insn) 173 + { 174 + return insn->prefixes.nbytes; 175 + } 176 + static inline int insn_offset_vex_prefix(struct insn *insn) 177 + { 178 + return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; 179 + } 180 + static inline int insn_offset_opcode(struct insn *insn) 181 + { 182 + return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; 183 + } 184 + static inline int insn_offset_modrm(struct insn *insn) 185 + { 186 + return insn_offset_opcode(insn) + insn->opcode.nbytes; 187 + } 188 + static inline int insn_offset_sib(struct insn *insn) 189 + { 190 + return insn_offset_modrm(insn) + insn->modrm.nbytes; 191 + } 192 + static inline int insn_offset_displacement(struct insn *insn) 193 + { 194 + return insn_offset_sib(insn) + insn->sib.nbytes; 195 + } 196 + static inline int insn_offset_immediate(struct insn *insn) 197 + { 198 + return insn_offset_displacement(insn) + insn->displacement.nbytes; 199 + } 200 + 201 + #endif /* _ASM_X86_INSN_H */
+984
tools/objtool/arch/x86/insn/x86-opcode-map.txt
··· 1 + # x86 Opcode Maps 2 + # 3 + # This is (mostly) based on following documentations. 4 + # - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C 5 + # (#326018-047US, June 2013) 6 + # 7 + #<Opcode maps> 8 + # Table: table-name 9 + # Referrer: escaped-name 10 + # AVXcode: avx-code 11 + # opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] 12 + # (or) 13 + # opcode: escape # escaped-name 14 + # EndTable 15 + # 16 + #<group maps> 17 + # GrpTable: GrpXXX 18 + # reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] 19 + # EndTable 20 + # 21 + # AVX Superscripts 22 + # (v): this opcode requires VEX prefix. 23 + # (v1): this opcode only supports 128bit VEX. 24 + # 25 + # Last Prefix Superscripts 26 + # - (66): the last prefix is 0x66 27 + # - (F3): the last prefix is 0xF3 28 + # - (F2): the last prefix is 0xF2 29 + # - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) 30 + # - (66&F2): Both 0x66 and 0xF2 prefixes are specified. 31 + 32 + Table: one byte opcode 33 + Referrer: 34 + AVXcode: 35 + # 0x00 - 0x0f 36 + 00: ADD Eb,Gb 37 + 01: ADD Ev,Gv 38 + 02: ADD Gb,Eb 39 + 03: ADD Gv,Ev 40 + 04: ADD AL,Ib 41 + 05: ADD rAX,Iz 42 + 06: PUSH ES (i64) 43 + 07: POP ES (i64) 44 + 08: OR Eb,Gb 45 + 09: OR Ev,Gv 46 + 0a: OR Gb,Eb 47 + 0b: OR Gv,Ev 48 + 0c: OR AL,Ib 49 + 0d: OR rAX,Iz 50 + 0e: PUSH CS (i64) 51 + 0f: escape # 2-byte escape 52 + # 0x10 - 0x1f 53 + 10: ADC Eb,Gb 54 + 11: ADC Ev,Gv 55 + 12: ADC Gb,Eb 56 + 13: ADC Gv,Ev 57 + 14: ADC AL,Ib 58 + 15: ADC rAX,Iz 59 + 16: PUSH SS (i64) 60 + 17: POP SS (i64) 61 + 18: SBB Eb,Gb 62 + 19: SBB Ev,Gv 63 + 1a: SBB Gb,Eb 64 + 1b: SBB Gv,Ev 65 + 1c: SBB AL,Ib 66 + 1d: SBB rAX,Iz 67 + 1e: PUSH DS (i64) 68 + 1f: POP DS (i64) 69 + # 0x20 - 0x2f 70 + 20: AND Eb,Gb 71 + 21: AND Ev,Gv 72 + 22: AND Gb,Eb 73 + 23: AND Gv,Ev 74 + 24: AND AL,Ib 75 + 25: AND rAx,Iz 76 + 26: SEG=ES (Prefix) 77 + 27: DAA (i64) 78 + 28: SUB Eb,Gb 79 + 29: SUB Ev,Gv 80 + 2a: SUB Gb,Eb 81 + 2b: SUB Gv,Ev 82 + 2c: SUB AL,Ib 83 + 2d: SUB rAX,Iz 84 + 2e: SEG=CS (Prefix) 85 + 2f: DAS (i64) 86 + # 0x30 - 0x3f 87 + 30: XOR Eb,Gb 88 + 31: XOR Ev,Gv 89 + 32: XOR Gb,Eb 90 + 33: XOR Gv,Ev 91 + 34: XOR AL,Ib 92 + 35: XOR rAX,Iz 93 + 36: SEG=SS (Prefix) 94 + 37: AAA (i64) 95 + 38: CMP Eb,Gb 96 + 39: CMP Ev,Gv 97 + 3a: CMP Gb,Eb 98 + 3b: CMP Gv,Ev 99 + 3c: CMP AL,Ib 100 + 3d: CMP rAX,Iz 101 + 3e: SEG=DS (Prefix) 102 + 3f: AAS (i64) 103 + # 0x40 - 0x4f 104 + 40: INC eAX (i64) | REX (o64) 105 + 41: INC eCX (i64) | REX.B (o64) 106 + 42: INC eDX (i64) | REX.X (o64) 107 + 43: INC eBX (i64) | REX.XB (o64) 108 + 44: INC eSP (i64) | REX.R (o64) 109 + 45: INC eBP (i64) | REX.RB (o64) 110 + 46: INC eSI (i64) | REX.RX (o64) 111 + 47: INC eDI (i64) | REX.RXB (o64) 112 + 48: DEC eAX (i64) | REX.W (o64) 113 + 49: DEC eCX (i64) | REX.WB (o64) 114 + 4a: DEC eDX (i64) | REX.WX (o64) 115 + 4b: DEC eBX (i64) | REX.WXB (o64) 116 + 4c: DEC eSP (i64) | REX.WR (o64) 117 + 4d: DEC eBP (i64) | REX.WRB (o64) 118 + 4e: DEC eSI (i64) | REX.WRX (o64) 119 + 4f: DEC eDI (i64) | REX.WRXB (o64) 120 + # 0x50 - 0x5f 121 + 50: PUSH rAX/r8 (d64) 122 + 51: PUSH rCX/r9 (d64) 123 + 52: PUSH rDX/r10 (d64) 124 + 53: PUSH rBX/r11 (d64) 125 + 54: PUSH rSP/r12 (d64) 126 + 55: PUSH rBP/r13 (d64) 127 + 56: PUSH rSI/r14 (d64) 128 + 57: PUSH rDI/r15 (d64) 129 + 58: POP rAX/r8 (d64) 130 + 59: POP rCX/r9 (d64) 131 + 5a: POP rDX/r10 (d64) 132 + 5b: POP rBX/r11 (d64) 133 + 5c: POP rSP/r12 (d64) 134 + 5d: POP rBP/r13 (d64) 135 + 5e: POP rSI/r14 (d64) 136 + 5f: POP rDI/r15 (d64) 137 + # 0x60 - 0x6f 138 + 60: PUSHA/PUSHAD (i64) 139 + 61: POPA/POPAD (i64) 140 + 62: BOUND Gv,Ma (i64) 141 + 63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) 142 + 64: SEG=FS (Prefix) 143 + 65: SEG=GS (Prefix) 144 + 66: Operand-Size (Prefix) 145 + 67: Address-Size (Prefix) 146 + 68: PUSH Iz (d64) 147 + 69: IMUL Gv,Ev,Iz 148 + 6a: PUSH Ib (d64) 149 + 6b: IMUL Gv,Ev,Ib 150 + 6c: INS/INSB Yb,DX 151 + 6d: INS/INSW/INSD Yz,DX 152 + 6e: OUTS/OUTSB DX,Xb 153 + 6f: OUTS/OUTSW/OUTSD DX,Xz 154 + # 0x70 - 0x7f 155 + 70: JO Jb 156 + 71: JNO Jb 157 + 72: JB/JNAE/JC Jb 158 + 73: JNB/JAE/JNC Jb 159 + 74: JZ/JE Jb 160 + 75: JNZ/JNE Jb 161 + 76: JBE/JNA Jb 162 + 77: JNBE/JA Jb 163 + 78: JS Jb 164 + 79: JNS Jb 165 + 7a: JP/JPE Jb 166 + 7b: JNP/JPO Jb 167 + 7c: JL/JNGE Jb 168 + 7d: JNL/JGE Jb 169 + 7e: JLE/JNG Jb 170 + 7f: JNLE/JG Jb 171 + # 0x80 - 0x8f 172 + 80: Grp1 Eb,Ib (1A) 173 + 81: Grp1 Ev,Iz (1A) 174 + 82: Grp1 Eb,Ib (1A),(i64) 175 + 83: Grp1 Ev,Ib (1A) 176 + 84: TEST Eb,Gb 177 + 85: TEST Ev,Gv 178 + 86: XCHG Eb,Gb 179 + 87: XCHG Ev,Gv 180 + 88: MOV Eb,Gb 181 + 89: MOV Ev,Gv 182 + 8a: MOV Gb,Eb 183 + 8b: MOV Gv,Ev 184 + 8c: MOV Ev,Sw 185 + 8d: LEA Gv,M 186 + 8e: MOV Sw,Ew 187 + 8f: Grp1A (1A) | POP Ev (d64) 188 + # 0x90 - 0x9f 189 + 90: NOP | PAUSE (F3) | XCHG r8,rAX 190 + 91: XCHG rCX/r9,rAX 191 + 92: XCHG rDX/r10,rAX 192 + 93: XCHG rBX/r11,rAX 193 + 94: XCHG rSP/r12,rAX 194 + 95: XCHG rBP/r13,rAX 195 + 96: XCHG rSI/r14,rAX 196 + 97: XCHG rDI/r15,rAX 197 + 98: CBW/CWDE/CDQE 198 + 99: CWD/CDQ/CQO 199 + 9a: CALLF Ap (i64) 200 + 9b: FWAIT/WAIT 201 + 9c: PUSHF/D/Q Fv (d64) 202 + 9d: POPF/D/Q Fv (d64) 203 + 9e: SAHF 204 + 9f: LAHF 205 + # 0xa0 - 0xaf 206 + a0: MOV AL,Ob 207 + a1: MOV rAX,Ov 208 + a2: MOV Ob,AL 209 + a3: MOV Ov,rAX 210 + a4: MOVS/B Yb,Xb 211 + a5: MOVS/W/D/Q Yv,Xv 212 + a6: CMPS/B Xb,Yb 213 + a7: CMPS/W/D Xv,Yv 214 + a8: TEST AL,Ib 215 + a9: TEST rAX,Iz 216 + aa: STOS/B Yb,AL 217 + ab: STOS/W/D/Q Yv,rAX 218 + ac: LODS/B AL,Xb 219 + ad: LODS/W/D/Q rAX,Xv 220 + ae: SCAS/B AL,Yb 221 + # Note: The May 2011 Intel manual shows Xv for the second parameter of the 222 + # next instruction but Yv is correct 223 + af: SCAS/W/D/Q rAX,Yv 224 + # 0xb0 - 0xbf 225 + b0: MOV AL/R8L,Ib 226 + b1: MOV CL/R9L,Ib 227 + b2: MOV DL/R10L,Ib 228 + b3: MOV BL/R11L,Ib 229 + b4: MOV AH/R12L,Ib 230 + b5: MOV CH/R13L,Ib 231 + b6: MOV DH/R14L,Ib 232 + b7: MOV BH/R15L,Ib 233 + b8: MOV rAX/r8,Iv 234 + b9: MOV rCX/r9,Iv 235 + ba: MOV rDX/r10,Iv 236 + bb: MOV rBX/r11,Iv 237 + bc: MOV rSP/r12,Iv 238 + bd: MOV rBP/r13,Iv 239 + be: MOV rSI/r14,Iv 240 + bf: MOV rDI/r15,Iv 241 + # 0xc0 - 0xcf 242 + c0: Grp2 Eb,Ib (1A) 243 + c1: Grp2 Ev,Ib (1A) 244 + c2: RETN Iw (f64) 245 + c3: RETN 246 + c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) 247 + c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) 248 + c6: Grp11A Eb,Ib (1A) 249 + c7: Grp11B Ev,Iz (1A) 250 + c8: ENTER Iw,Ib 251 + c9: LEAVE (d64) 252 + ca: RETF Iw 253 + cb: RETF 254 + cc: INT3 255 + cd: INT Ib 256 + ce: INTO (i64) 257 + cf: IRET/D/Q 258 + # 0xd0 - 0xdf 259 + d0: Grp2 Eb,1 (1A) 260 + d1: Grp2 Ev,1 (1A) 261 + d2: Grp2 Eb,CL (1A) 262 + d3: Grp2 Ev,CL (1A) 263 + d4: AAM Ib (i64) 264 + d5: AAD Ib (i64) 265 + d6: 266 + d7: XLAT/XLATB 267 + d8: ESC 268 + d9: ESC 269 + da: ESC 270 + db: ESC 271 + dc: ESC 272 + dd: ESC 273 + de: ESC 274 + df: ESC 275 + # 0xe0 - 0xef 276 + # Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix 277 + # in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation 278 + # to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD. 279 + e0: LOOPNE/LOOPNZ Jb (f64) 280 + e1: LOOPE/LOOPZ Jb (f64) 281 + e2: LOOP Jb (f64) 282 + e3: JrCXZ Jb (f64) 283 + e4: IN AL,Ib 284 + e5: IN eAX,Ib 285 + e6: OUT Ib,AL 286 + e7: OUT Ib,eAX 287 + # With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset 288 + # in "near" jumps and calls is 16-bit. For CALL, 289 + # push of return address is 16-bit wide, RSP is decremented by 2 290 + # but is not truncated to 16 bits, unlike RIP. 291 + e8: CALL Jz (f64) 292 + e9: JMP-near Jz (f64) 293 + ea: JMP-far Ap (i64) 294 + eb: JMP-short Jb (f64) 295 + ec: IN AL,DX 296 + ed: IN eAX,DX 297 + ee: OUT DX,AL 298 + ef: OUT DX,eAX 299 + # 0xf0 - 0xff 300 + f0: LOCK (Prefix) 301 + f1: 302 + f2: REPNE (Prefix) | XACQUIRE (Prefix) 303 + f3: REP/REPE (Prefix) | XRELEASE (Prefix) 304 + f4: HLT 305 + f5: CMC 306 + f6: Grp3_1 Eb (1A) 307 + f7: Grp3_2 Ev (1A) 308 + f8: CLC 309 + f9: STC 310 + fa: CLI 311 + fb: STI 312 + fc: CLD 313 + fd: STD 314 + fe: Grp4 (1A) 315 + ff: Grp5 (1A) 316 + EndTable 317 + 318 + Table: 2-byte opcode (0x0f) 319 + Referrer: 2-byte escape 320 + AVXcode: 1 321 + # 0x0f 0x00-0x0f 322 + 00: Grp6 (1A) 323 + 01: Grp7 (1A) 324 + 02: LAR Gv,Ew 325 + 03: LSL Gv,Ew 326 + 04: 327 + 05: SYSCALL (o64) 328 + 06: CLTS 329 + 07: SYSRET (o64) 330 + 08: INVD 331 + 09: WBINVD 332 + 0a: 333 + 0b: UD2 (1B) 334 + 0c: 335 + # AMD's prefetch group. Intel supports prefetchw(/1) only. 336 + 0d: GrpP 337 + 0e: FEMMS 338 + # 3DNow! uses the last imm byte as opcode extension. 339 + 0f: 3DNow! Pq,Qq,Ib 340 + # 0x0f 0x10-0x1f 341 + # NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands 342 + # but it actually has operands. And also, vmovss and vmovsd only accept 128bit. 343 + # MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. 344 + # Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming 345 + # Reference A.1 346 + 10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) 347 + 11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) 348 + 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) 349 + 13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) 350 + 14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) 351 + 15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) 352 + 16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) 353 + 17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) 354 + 18: Grp16 (1A) 355 + 19: 356 + # Intel SDM opcode map does not list MPX instructions. For now using Gv for 357 + # bnd registers and Ev for everything else is OK because the instruction 358 + # decoder does not use the information except as an indication that there is 359 + # a ModR/M byte. 360 + 1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev 361 + 1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv 362 + 1c: 363 + 1d: 364 + 1e: 365 + 1f: NOP Ev 366 + # 0x0f 0x20-0x2f 367 + 20: MOV Rd,Cd 368 + 21: MOV Rd,Dd 369 + 22: MOV Cd,Rd 370 + 23: MOV Dd,Rd 371 + 24: 372 + 25: 373 + 26: 374 + 27: 375 + 28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) 376 + 29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) 377 + 2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) 378 + 2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) 379 + 2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) 380 + 2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) 381 + 2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) 382 + 2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) 383 + # 0x0f 0x30-0x3f 384 + 30: WRMSR 385 + 31: RDTSC 386 + 32: RDMSR 387 + 33: RDPMC 388 + 34: SYSENTER 389 + 35: SYSEXIT 390 + 36: 391 + 37: GETSEC 392 + 38: escape # 3-byte escape 1 393 + 39: 394 + 3a: escape # 3-byte escape 2 395 + 3b: 396 + 3c: 397 + 3d: 398 + 3e: 399 + 3f: 400 + # 0x0f 0x40-0x4f 401 + 40: CMOVO Gv,Ev 402 + 41: CMOVNO Gv,Ev 403 + 42: CMOVB/C/NAE Gv,Ev 404 + 43: CMOVAE/NB/NC Gv,Ev 405 + 44: CMOVE/Z Gv,Ev 406 + 45: CMOVNE/NZ Gv,Ev 407 + 46: CMOVBE/NA Gv,Ev 408 + 47: CMOVA/NBE Gv,Ev 409 + 48: CMOVS Gv,Ev 410 + 49: CMOVNS Gv,Ev 411 + 4a: CMOVP/PE Gv,Ev 412 + 4b: CMOVNP/PO Gv,Ev 413 + 4c: CMOVL/NGE Gv,Ev 414 + 4d: CMOVNL/GE Gv,Ev 415 + 4e: CMOVLE/NG Gv,Ev 416 + 4f: CMOVNLE/G Gv,Ev 417 + # 0x0f 0x50-0x5f 418 + 50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) 419 + 51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) 420 + 52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) 421 + 53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) 422 + 54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) 423 + 55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) 424 + 56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) 425 + 57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) 426 + 58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) 427 + 59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) 428 + 5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) 429 + 5b: vcvtdq2ps Vps,Wdq | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) 430 + 5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) 431 + 5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) 432 + 5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) 433 + 5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) 434 + # 0x0f 0x60-0x6f 435 + 60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) 436 + 61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) 437 + 62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) 438 + 63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) 439 + 64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) 440 + 65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) 441 + 66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) 442 + 67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) 443 + 68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) 444 + 69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) 445 + 6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) 446 + 6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) 447 + 6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) 448 + 6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) 449 + 6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) 450 + 6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqu Vx,Wx (F3) 451 + # 0x0f 0x70-0x7f 452 + 70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) 453 + 71: Grp12 (1A) 454 + 72: Grp13 (1A) 455 + 73: Grp14 (1A) 456 + 74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) 457 + 75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) 458 + 76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) 459 + # Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. 460 + 77: emms | vzeroupper | vzeroall 461 + 78: VMREAD Ey,Gy 462 + 79: VMWRITE Gy,Ey 463 + 7a: 464 + 7b: 465 + 7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) 466 + 7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) 467 + 7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) 468 + 7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqu Wx,Vx (F3) 469 + # 0x0f 0x80-0x8f 470 + # Note: "forced64" is Intel CPU behavior (see comment about CALL insn). 471 + 80: JO Jz (f64) 472 + 81: JNO Jz (f64) 473 + 82: JB/JC/JNAE Jz (f64) 474 + 83: JAE/JNB/JNC Jz (f64) 475 + 84: JE/JZ Jz (f64) 476 + 85: JNE/JNZ Jz (f64) 477 + 86: JBE/JNA Jz (f64) 478 + 87: JA/JNBE Jz (f64) 479 + 88: JS Jz (f64) 480 + 89: JNS Jz (f64) 481 + 8a: JP/JPE Jz (f64) 482 + 8b: JNP/JPO Jz (f64) 483 + 8c: JL/JNGE Jz (f64) 484 + 8d: JNL/JGE Jz (f64) 485 + 8e: JLE/JNG Jz (f64) 486 + 8f: JNLE/JG Jz (f64) 487 + # 0x0f 0x90-0x9f 488 + 90: SETO Eb 489 + 91: SETNO Eb 490 + 92: SETB/C/NAE Eb 491 + 93: SETAE/NB/NC Eb 492 + 94: SETE/Z Eb 493 + 95: SETNE/NZ Eb 494 + 96: SETBE/NA Eb 495 + 97: SETA/NBE Eb 496 + 98: SETS Eb 497 + 99: SETNS Eb 498 + 9a: SETP/PE Eb 499 + 9b: SETNP/PO Eb 500 + 9c: SETL/NGE Eb 501 + 9d: SETNL/GE Eb 502 + 9e: SETLE/NG Eb 503 + 9f: SETNLE/G Eb 504 + # 0x0f 0xa0-0xaf 505 + a0: PUSH FS (d64) 506 + a1: POP FS (d64) 507 + a2: CPUID 508 + a3: BT Ev,Gv 509 + a4: SHLD Ev,Gv,Ib 510 + a5: SHLD Ev,Gv,CL 511 + a6: GrpPDLK 512 + a7: GrpRNG 513 + a8: PUSH GS (d64) 514 + a9: POP GS (d64) 515 + aa: RSM 516 + ab: BTS Ev,Gv 517 + ac: SHRD Ev,Gv,Ib 518 + ad: SHRD Ev,Gv,CL 519 + ae: Grp15 (1A),(1C) 520 + af: IMUL Gv,Ev 521 + # 0x0f 0xb0-0xbf 522 + b0: CMPXCHG Eb,Gb 523 + b1: CMPXCHG Ev,Gv 524 + b2: LSS Gv,Mp 525 + b3: BTR Ev,Gv 526 + b4: LFS Gv,Mp 527 + b5: LGS Gv,Mp 528 + b6: MOVZX Gv,Eb 529 + b7: MOVZX Gv,Ew 530 + b8: JMPE (!F3) | POPCNT Gv,Ev (F3) 531 + b9: Grp10 (1A) 532 + ba: Grp8 Ev,Ib (1A) 533 + bb: BTC Ev,Gv 534 + bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) 535 + bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) 536 + be: MOVSX Gv,Eb 537 + bf: MOVSX Gv,Ew 538 + # 0x0f 0xc0-0xcf 539 + c0: XADD Eb,Gb 540 + c1: XADD Ev,Gv 541 + 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) 542 + c3: movnti My,Gy 543 + c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) 544 + c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) 545 + c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) 546 + c7: Grp9 (1A) 547 + c8: BSWAP RAX/EAX/R8/R8D 548 + c9: BSWAP RCX/ECX/R9/R9D 549 + ca: BSWAP RDX/EDX/R10/R10D 550 + cb: BSWAP RBX/EBX/R11/R11D 551 + cc: BSWAP RSP/ESP/R12/R12D 552 + cd: BSWAP RBP/EBP/R13/R13D 553 + ce: BSWAP RSI/ESI/R14/R14D 554 + cf: BSWAP RDI/EDI/R15/R15D 555 + # 0x0f 0xd0-0xdf 556 + d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) 557 + d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) 558 + d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) 559 + d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) 560 + d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) 561 + d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) 562 + d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) 563 + d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) 564 + d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) 565 + d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) 566 + da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) 567 + db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) 568 + dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) 569 + dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) 570 + de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) 571 + df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) 572 + # 0x0f 0xe0-0xef 573 + e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) 574 + e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) 575 + e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) 576 + e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) 577 + e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) 578 + e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) 579 + e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtpd2dq Vx,Wpd (F2) 580 + e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) 581 + e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) 582 + e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) 583 + ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) 584 + eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) 585 + ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) 586 + ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) 587 + ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) 588 + ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) 589 + # 0x0f 0xf0-0xff 590 + f0: vlddqu Vx,Mx (F2) 591 + f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) 592 + f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) 593 + f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) 594 + f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) 595 + f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) 596 + f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) 597 + f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) 598 + f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) 599 + f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) 600 + fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) 601 + fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) 602 + fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) 603 + fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) 604 + fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) 605 + ff: 606 + EndTable 607 + 608 + Table: 3-byte opcode 1 (0x0f 0x38) 609 + Referrer: 3-byte escape 1 610 + AVXcode: 2 611 + # 0x0f 0x38 0x00-0x0f 612 + 00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) 613 + 01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) 614 + 02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) 615 + 03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) 616 + 04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) 617 + 05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) 618 + 06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) 619 + 07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) 620 + 08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) 621 + 09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) 622 + 0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) 623 + 0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) 624 + 0c: vpermilps Vx,Hx,Wx (66),(v) 625 + 0d: vpermilpd Vx,Hx,Wx (66),(v) 626 + 0e: vtestps Vx,Wx (66),(v) 627 + 0f: vtestpd Vx,Wx (66),(v) 628 + # 0x0f 0x38 0x10-0x1f 629 + 10: pblendvb Vdq,Wdq (66) 630 + 11: 631 + 12: 632 + 13: vcvtph2ps Vx,Wx,Ib (66),(v) 633 + 14: blendvps Vdq,Wdq (66) 634 + 15: blendvpd Vdq,Wdq (66) 635 + 16: vpermps Vqq,Hqq,Wqq (66),(v) 636 + 17: vptest Vx,Wx (66) 637 + 18: vbroadcastss Vx,Wd (66),(v) 638 + 19: vbroadcastsd Vqq,Wq (66),(v) 639 + 1a: vbroadcastf128 Vqq,Mdq (66),(v) 640 + 1b: 641 + 1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) 642 + 1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) 643 + 1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) 644 + 1f: 645 + # 0x0f 0x38 0x20-0x2f 646 + 20: vpmovsxbw Vx,Ux/Mq (66),(v1) 647 + 21: vpmovsxbd Vx,Ux/Md (66),(v1) 648 + 22: vpmovsxbq Vx,Ux/Mw (66),(v1) 649 + 23: vpmovsxwd Vx,Ux/Mq (66),(v1) 650 + 24: vpmovsxwq Vx,Ux/Md (66),(v1) 651 + 25: vpmovsxdq Vx,Ux/Mq (66),(v1) 652 + 26: 653 + 27: 654 + 28: vpmuldq Vx,Hx,Wx (66),(v1) 655 + 29: vpcmpeqq Vx,Hx,Wx (66),(v1) 656 + 2a: vmovntdqa Vx,Mx (66),(v1) 657 + 2b: vpackusdw Vx,Hx,Wx (66),(v1) 658 + 2c: vmaskmovps Vx,Hx,Mx (66),(v) 659 + 2d: vmaskmovpd Vx,Hx,Mx (66),(v) 660 + 2e: vmaskmovps Mx,Hx,Vx (66),(v) 661 + 2f: vmaskmovpd Mx,Hx,Vx (66),(v) 662 + # 0x0f 0x38 0x30-0x3f 663 + 30: vpmovzxbw Vx,Ux/Mq (66),(v1) 664 + 31: vpmovzxbd Vx,Ux/Md (66),(v1) 665 + 32: vpmovzxbq Vx,Ux/Mw (66),(v1) 666 + 33: vpmovzxwd Vx,Ux/Mq (66),(v1) 667 + 34: vpmovzxwq Vx,Ux/Md (66),(v1) 668 + 35: vpmovzxdq Vx,Ux/Mq (66),(v1) 669 + 36: vpermd Vqq,Hqq,Wqq (66),(v) 670 + 37: vpcmpgtq Vx,Hx,Wx (66),(v1) 671 + 38: vpminsb Vx,Hx,Wx (66),(v1) 672 + 39: vpminsd Vx,Hx,Wx (66),(v1) 673 + 3a: vpminuw Vx,Hx,Wx (66),(v1) 674 + 3b: vpminud Vx,Hx,Wx (66),(v1) 675 + 3c: vpmaxsb Vx,Hx,Wx (66),(v1) 676 + 3d: vpmaxsd Vx,Hx,Wx (66),(v1) 677 + 3e: vpmaxuw Vx,Hx,Wx (66),(v1) 678 + 3f: vpmaxud Vx,Hx,Wx (66),(v1) 679 + # 0x0f 0x38 0x40-0x8f 680 + 40: vpmulld Vx,Hx,Wx (66),(v1) 681 + 41: vphminposuw Vdq,Wdq (66),(v1) 682 + 42: 683 + 43: 684 + 44: 685 + 45: vpsrlvd/q Vx,Hx,Wx (66),(v) 686 + 46: vpsravd Vx,Hx,Wx (66),(v) 687 + 47: vpsllvd/q Vx,Hx,Wx (66),(v) 688 + # Skip 0x48-0x57 689 + 58: vpbroadcastd Vx,Wx (66),(v) 690 + 59: vpbroadcastq Vx,Wx (66),(v) 691 + 5a: vbroadcasti128 Vqq,Mdq (66),(v) 692 + # Skip 0x5b-0x77 693 + 78: vpbroadcastb Vx,Wx (66),(v) 694 + 79: vpbroadcastw Vx,Wx (66),(v) 695 + # Skip 0x7a-0x7f 696 + 80: INVEPT Gy,Mdq (66) 697 + 81: INVPID Gy,Mdq (66) 698 + 82: INVPCID Gy,Mdq (66) 699 + 8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) 700 + 8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) 701 + # 0x0f 0x38 0x90-0xbf (FMA) 702 + 90: vgatherdd/q Vx,Hx,Wx (66),(v) 703 + 91: vgatherqd/q Vx,Hx,Wx (66),(v) 704 + 92: vgatherdps/d Vx,Hx,Wx (66),(v) 705 + 93: vgatherqps/d Vx,Hx,Wx (66),(v) 706 + 94: 707 + 95: 708 + 96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) 709 + 97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) 710 + 98: vfmadd132ps/d Vx,Hx,Wx (66),(v) 711 + 99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) 712 + 9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) 713 + 9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) 714 + 9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) 715 + 9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) 716 + 9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) 717 + 9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) 718 + a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) 719 + a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) 720 + a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) 721 + a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) 722 + aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) 723 + ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) 724 + ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) 725 + ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) 726 + ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) 727 + af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) 728 + b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) 729 + b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) 730 + b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) 731 + b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) 732 + ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) 733 + bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) 734 + bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) 735 + bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) 736 + be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) 737 + bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) 738 + # 0x0f 0x38 0xc0-0xff 739 + c8: sha1nexte Vdq,Wdq 740 + c9: sha1msg1 Vdq,Wdq 741 + ca: sha1msg2 Vdq,Wdq 742 + cb: sha256rnds2 Vdq,Wdq 743 + cc: sha256msg1 Vdq,Wdq 744 + cd: sha256msg2 Vdq,Wdq 745 + db: VAESIMC Vdq,Wdq (66),(v1) 746 + dc: VAESENC Vdq,Hdq,Wdq (66),(v1) 747 + dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) 748 + de: VAESDEC Vdq,Hdq,Wdq (66),(v1) 749 + df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) 750 + f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) 751 + f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) 752 + f2: ANDN Gy,By,Ey (v) 753 + f3: Grp17 (1A) 754 + f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) 755 + f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) 756 + f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) 757 + EndTable 758 + 759 + Table: 3-byte opcode 2 (0x0f 0x3a) 760 + Referrer: 3-byte escape 2 761 + AVXcode: 3 762 + # 0x0f 0x3a 0x00-0xff 763 + 00: vpermq Vqq,Wqq,Ib (66),(v) 764 + 01: vpermpd Vqq,Wqq,Ib (66),(v) 765 + 02: vpblendd Vx,Hx,Wx,Ib (66),(v) 766 + 03: 767 + 04: vpermilps Vx,Wx,Ib (66),(v) 768 + 05: vpermilpd Vx,Wx,Ib (66),(v) 769 + 06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) 770 + 07: 771 + 08: vroundps Vx,Wx,Ib (66) 772 + 09: vroundpd Vx,Wx,Ib (66) 773 + 0a: vroundss Vss,Wss,Ib (66),(v1) 774 + 0b: vroundsd Vsd,Wsd,Ib (66),(v1) 775 + 0c: vblendps Vx,Hx,Wx,Ib (66) 776 + 0d: vblendpd Vx,Hx,Wx,Ib (66) 777 + 0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) 778 + 0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) 779 + 14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) 780 + 15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) 781 + 16: vpextrd/q Ey,Vdq,Ib (66),(v1) 782 + 17: vextractps Ed,Vdq,Ib (66),(v1) 783 + 18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) 784 + 19: vextractf128 Wdq,Vqq,Ib (66),(v) 785 + 1d: vcvtps2ph Wx,Vx,Ib (66),(v) 786 + 20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) 787 + 21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) 788 + 22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) 789 + 38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) 790 + 39: vextracti128 Wdq,Vqq,Ib (66),(v) 791 + 40: vdpps Vx,Hx,Wx,Ib (66) 792 + 41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) 793 + 42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) 794 + 44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) 795 + 46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) 796 + 4a: vblendvps Vx,Hx,Wx,Lx (66),(v) 797 + 4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) 798 + 4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) 799 + 60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) 800 + 61: vpcmpestri Vdq,Wdq,Ib (66),(v1) 801 + 62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) 802 + 63: vpcmpistri Vdq,Wdq,Ib (66),(v1) 803 + cc: sha1rnds4 Vdq,Wdq,Ib 804 + df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) 805 + f0: RORX Gy,Ey,Ib (F2),(v) 806 + EndTable 807 + 808 + GrpTable: Grp1 809 + 0: ADD 810 + 1: OR 811 + 2: ADC 812 + 3: SBB 813 + 4: AND 814 + 5: SUB 815 + 6: XOR 816 + 7: CMP 817 + EndTable 818 + 819 + GrpTable: Grp1A 820 + 0: POP 821 + EndTable 822 + 823 + GrpTable: Grp2 824 + 0: ROL 825 + 1: ROR 826 + 2: RCL 827 + 3: RCR 828 + 4: SHL/SAL 829 + 5: SHR 830 + 6: 831 + 7: SAR 832 + EndTable 833 + 834 + GrpTable: Grp3_1 835 + 0: TEST Eb,Ib 836 + 1: 837 + 2: NOT Eb 838 + 3: NEG Eb 839 + 4: MUL AL,Eb 840 + 5: IMUL AL,Eb 841 + 6: DIV AL,Eb 842 + 7: IDIV AL,Eb 843 + EndTable 844 + 845 + GrpTable: Grp3_2 846 + 0: TEST Ev,Iz 847 + 1: 848 + 2: NOT Ev 849 + 3: NEG Ev 850 + 4: MUL rAX,Ev 851 + 5: IMUL rAX,Ev 852 + 6: DIV rAX,Ev 853 + 7: IDIV rAX,Ev 854 + EndTable 855 + 856 + GrpTable: Grp4 857 + 0: INC Eb 858 + 1: DEC Eb 859 + EndTable 860 + 861 + GrpTable: Grp5 862 + 0: INC Ev 863 + 1: DEC Ev 864 + # Note: "forced64" is Intel CPU behavior (see comment about CALL insn). 865 + 2: CALLN Ev (f64) 866 + 3: CALLF Ep 867 + 4: JMPN Ev (f64) 868 + 5: JMPF Mp 869 + 6: PUSH Ev (d64) 870 + 7: 871 + EndTable 872 + 873 + GrpTable: Grp6 874 + 0: SLDT Rv/Mw 875 + 1: STR Rv/Mw 876 + 2: LLDT Ew 877 + 3: LTR Ew 878 + 4: VERR Ew 879 + 5: VERW Ew 880 + EndTable 881 + 882 + GrpTable: Grp7 883 + 0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) 884 + 1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) 885 + 2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) 886 + 3: LIDT Ms 887 + 4: SMSW Mw/Rv 888 + 5: rdpkru (110),(11B) | wrpkru (111),(11B) 889 + 6: LMSW Ew 890 + 7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) 891 + EndTable 892 + 893 + GrpTable: Grp8 894 + 4: BT 895 + 5: BTS 896 + 6: BTR 897 + 7: BTC 898 + EndTable 899 + 900 + GrpTable: Grp9 901 + 1: CMPXCHG8B/16B Mq/Mdq 902 + 3: xrstors 903 + 4: xsavec 904 + 5: xsaves 905 + 6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) 906 + 7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) 907 + EndTable 908 + 909 + GrpTable: Grp10 910 + EndTable 911 + 912 + # Grp11A and Grp11B are expressed as Grp11 in Intel SDM 913 + GrpTable: Grp11A 914 + 0: MOV Eb,Ib 915 + 7: XABORT Ib (000),(11B) 916 + EndTable 917 + 918 + GrpTable: Grp11B 919 + 0: MOV Eb,Iz 920 + 7: XBEGIN Jz (000),(11B) 921 + EndTable 922 + 923 + GrpTable: Grp12 924 + 2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) 925 + 4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) 926 + 6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) 927 + EndTable 928 + 929 + GrpTable: Grp13 930 + 2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) 931 + 4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) 932 + 6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) 933 + EndTable 934 + 935 + GrpTable: Grp14 936 + 2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) 937 + 3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) 938 + 6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) 939 + 7: vpslldq Hx,Ux,Ib (66),(11B),(v1) 940 + EndTable 941 + 942 + GrpTable: Grp15 943 + 0: fxsave | RDFSBASE Ry (F3),(11B) 944 + 1: fxstor | RDGSBASE Ry (F3),(11B) 945 + 2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) 946 + 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) 947 + 4: XSAVE 948 + 5: XRSTOR | lfence (11B) 949 + 6: XSAVEOPT | clwb (66) | mfence (11B) 950 + 7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B) 951 + EndTable 952 + 953 + GrpTable: Grp16 954 + 0: prefetch NTA 955 + 1: prefetch T0 956 + 2: prefetch T1 957 + 3: prefetch T2 958 + EndTable 959 + 960 + GrpTable: Grp17 961 + 1: BLSR By,Ey (v) 962 + 2: BLSMSK By,Ey (v) 963 + 3: BLSI By,Ey (v) 964 + EndTable 965 + 966 + # AMD's Prefetch Group 967 + GrpTable: GrpP 968 + 0: PREFETCH 969 + 1: PREFETCHW 970 + EndTable 971 + 972 + GrpTable: GrpPDLK 973 + 0: MONTMUL 974 + 1: XSHA1 975 + 2: XSHA2 976 + EndTable 977 + 978 + GrpTable: GrpRNG 979 + 0: xstore-rng 980 + 1: xcrypt-ecb 981 + 2: xcrypt-cbc 982 + 4: xcrypt-cfb 983 + 5: xcrypt-ofb 984 + EndTable
+1072
tools/objtool/builtin-check.c
··· 1 + /* 2 + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 2 7 + * of the License, or (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + /* 19 + * objtool check: 20 + * 21 + * This command analyzes every .o file and ensures the validity of its stack 22 + * trace metadata. It enforces a set of rules on asm code and C inline 23 + * assembly code so that stack traces can be reliable. 24 + * 25 + * For more information, see tools/objtool/Documentation/stack-validation.txt. 26 + */ 27 + 28 + #include <string.h> 29 + #include <subcmd/parse-options.h> 30 + 31 + #include "builtin.h" 32 + #include "elf.h" 33 + #include "special.h" 34 + #include "arch.h" 35 + #include "warn.h" 36 + 37 + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 38 + 39 + #define STATE_FP_SAVED 0x1 40 + #define STATE_FP_SETUP 0x2 41 + #define STATE_FENTRY 0x4 42 + 43 + struct instruction { 44 + struct list_head list; 45 + struct section *sec; 46 + unsigned long offset; 47 + unsigned int len, state; 48 + unsigned char type; 49 + unsigned long immediate; 50 + bool alt_group, visited; 51 + struct symbol *call_dest; 52 + struct instruction *jump_dest; 53 + struct list_head alts; 54 + }; 55 + 56 + struct alternative { 57 + struct list_head list; 58 + struct instruction *insn; 59 + }; 60 + 61 + struct objtool_file { 62 + struct elf *elf; 63 + struct list_head insns; 64 + }; 65 + 66 + const char *objname; 67 + static bool nofp; 68 + 69 + static struct instruction *find_instruction(struct objtool_file *file, 70 + struct section *sec, 71 + unsigned long offset) 72 + { 73 + struct instruction *insn; 74 + 75 + list_for_each_entry(insn, &file->insns, list) 76 + if (insn->sec == sec && insn->offset == offset) 77 + return insn; 78 + 79 + return NULL; 80 + } 81 + 82 + /* 83 + * Check if the function has been manually whitelisted with the 84 + * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted 85 + * due to its use of a context switching instruction. 86 + */ 87 + static bool ignore_func(struct objtool_file *file, struct symbol *func) 88 + { 89 + struct section *macro_sec; 90 + struct rela *rela; 91 + struct instruction *insn; 92 + 93 + /* check for STACK_FRAME_NON_STANDARD */ 94 + macro_sec = find_section_by_name(file->elf, "__func_stack_frame_non_standard"); 95 + if (macro_sec && macro_sec->rela) 96 + list_for_each_entry(rela, &macro_sec->rela->relas, list) 97 + if (rela->sym->sec == func->sec && 98 + rela->addend == func->offset) 99 + return true; 100 + 101 + /* check if it has a context switching instruction */ 102 + insn = find_instruction(file, func->sec, func->offset); 103 + if (!insn) 104 + return false; 105 + list_for_each_entry_from(insn, &file->insns, list) { 106 + if (insn->sec != func->sec || 107 + insn->offset >= func->offset + func->len) 108 + break; 109 + if (insn->type == INSN_CONTEXT_SWITCH) 110 + return true; 111 + } 112 + 113 + return false; 114 + } 115 + 116 + /* 117 + * This checks to see if the given function is a "noreturn" function. 118 + * 119 + * For global functions which are outside the scope of this object file, we 120 + * have to keep a manual list of them. 121 + * 122 + * For local functions, we have to detect them manually by simply looking for 123 + * the lack of a return instruction. 124 + */ 125 + static bool dead_end_function(struct objtool_file *file, struct symbol *func) 126 + { 127 + int i; 128 + struct instruction *insn; 129 + bool empty = true; 130 + 131 + /* 132 + * Unfortunately these have to be hard coded because the noreturn 133 + * attribute isn't provided in ELF data. 134 + */ 135 + static const char * const global_noreturns[] = { 136 + "__stack_chk_fail", 137 + "panic", 138 + "do_exit", 139 + "__module_put_and_exit", 140 + "complete_and_exit", 141 + "kvm_spurious_fault", 142 + "__reiserfs_panic", 143 + "lbug_with_loc" 144 + }; 145 + 146 + if (func->bind == STB_WEAK) 147 + return false; 148 + 149 + if (func->bind == STB_GLOBAL) 150 + for (i = 0; i < ARRAY_SIZE(global_noreturns); i++) 151 + if (!strcmp(func->name, global_noreturns[i])) 152 + return true; 153 + 154 + if (!func->sec) 155 + return false; 156 + 157 + insn = find_instruction(file, func->sec, func->offset); 158 + if (!insn) 159 + return false; 160 + 161 + list_for_each_entry_from(insn, &file->insns, list) { 162 + if (insn->sec != func->sec || 163 + insn->offset >= func->offset + func->len) 164 + break; 165 + 166 + empty = false; 167 + 168 + if (insn->type == INSN_RETURN) 169 + return false; 170 + 171 + if (insn->type == INSN_JUMP_UNCONDITIONAL) { 172 + struct instruction *dest = insn->jump_dest; 173 + struct symbol *dest_func; 174 + 175 + if (!dest) 176 + /* sibling call to another file */ 177 + return false; 178 + 179 + if (dest->sec != func->sec || 180 + dest->offset < func->offset || 181 + dest->offset >= func->offset + func->len) { 182 + /* local sibling call */ 183 + dest_func = find_symbol_by_offset(dest->sec, 184 + dest->offset); 185 + if (!dest_func) 186 + continue; 187 + 188 + return dead_end_function(file, dest_func); 189 + } 190 + } 191 + 192 + if (insn->type == INSN_JUMP_DYNAMIC) 193 + /* sibling call */ 194 + return false; 195 + } 196 + 197 + return !empty; 198 + } 199 + 200 + /* 201 + * Call the arch-specific instruction decoder for all the instructions and add 202 + * them to the global insns list. 203 + */ 204 + static int decode_instructions(struct objtool_file *file) 205 + { 206 + struct section *sec; 207 + unsigned long offset; 208 + struct instruction *insn; 209 + int ret; 210 + 211 + INIT_LIST_HEAD(&file->insns); 212 + 213 + list_for_each_entry(sec, &file->elf->sections, list) { 214 + 215 + if (!(sec->sh.sh_flags & SHF_EXECINSTR)) 216 + continue; 217 + 218 + for (offset = 0; offset < sec->len; offset += insn->len) { 219 + insn = malloc(sizeof(*insn)); 220 + memset(insn, 0, sizeof(*insn)); 221 + 222 + INIT_LIST_HEAD(&insn->alts); 223 + insn->sec = sec; 224 + insn->offset = offset; 225 + 226 + ret = arch_decode_instruction(file->elf, sec, offset, 227 + sec->len - offset, 228 + &insn->len, &insn->type, 229 + &insn->immediate); 230 + if (ret) 231 + return ret; 232 + 233 + if (!insn->type || insn->type > INSN_LAST) { 234 + WARN_FUNC("invalid instruction type %d", 235 + insn->sec, insn->offset, insn->type); 236 + return -1; 237 + } 238 + 239 + list_add_tail(&insn->list, &file->insns); 240 + } 241 + } 242 + 243 + return 0; 244 + } 245 + 246 + /* 247 + * Warnings shouldn't be reported for ignored functions. 248 + */ 249 + static void get_ignores(struct objtool_file *file) 250 + { 251 + struct instruction *insn; 252 + struct section *sec; 253 + struct symbol *func; 254 + 255 + list_for_each_entry(sec, &file->elf->sections, list) { 256 + list_for_each_entry(func, &sec->symbols, list) { 257 + if (func->type != STT_FUNC) 258 + continue; 259 + 260 + if (!ignore_func(file, func)) 261 + continue; 262 + 263 + insn = find_instruction(file, sec, func->offset); 264 + if (!insn) 265 + continue; 266 + 267 + list_for_each_entry_from(insn, &file->insns, list) { 268 + if (insn->sec != func->sec || 269 + insn->offset >= func->offset + func->len) 270 + break; 271 + 272 + insn->visited = true; 273 + } 274 + } 275 + } 276 + } 277 + 278 + /* 279 + * Find the destination instructions for all jumps. 280 + */ 281 + static int get_jump_destinations(struct objtool_file *file) 282 + { 283 + struct instruction *insn; 284 + struct rela *rela; 285 + struct section *dest_sec; 286 + unsigned long dest_off; 287 + 288 + list_for_each_entry(insn, &file->insns, list) { 289 + if (insn->type != INSN_JUMP_CONDITIONAL && 290 + insn->type != INSN_JUMP_UNCONDITIONAL) 291 + continue; 292 + 293 + /* skip ignores */ 294 + if (insn->visited) 295 + continue; 296 + 297 + rela = find_rela_by_dest_range(insn->sec, insn->offset, 298 + insn->len); 299 + if (!rela) { 300 + dest_sec = insn->sec; 301 + dest_off = insn->offset + insn->len + insn->immediate; 302 + } else if (rela->sym->type == STT_SECTION) { 303 + dest_sec = rela->sym->sec; 304 + dest_off = rela->addend + 4; 305 + } else if (rela->sym->sec->idx) { 306 + dest_sec = rela->sym->sec; 307 + dest_off = rela->sym->sym.st_value + rela->addend + 4; 308 + } else { 309 + /* sibling call */ 310 + insn->jump_dest = 0; 311 + continue; 312 + } 313 + 314 + insn->jump_dest = find_instruction(file, dest_sec, dest_off); 315 + if (!insn->jump_dest) { 316 + 317 + /* 318 + * This is a special case where an alt instruction 319 + * jumps past the end of the section. These are 320 + * handled later in handle_group_alt(). 321 + */ 322 + if (!strcmp(insn->sec->name, ".altinstr_replacement")) 323 + continue; 324 + 325 + WARN_FUNC("can't find jump dest instruction at %s+0x%lx", 326 + insn->sec, insn->offset, dest_sec->name, 327 + dest_off); 328 + return -1; 329 + } 330 + } 331 + 332 + return 0; 333 + } 334 + 335 + /* 336 + * Find the destination instructions for all calls. 337 + */ 338 + static int get_call_destinations(struct objtool_file *file) 339 + { 340 + struct instruction *insn; 341 + unsigned long dest_off; 342 + struct rela *rela; 343 + 344 + list_for_each_entry(insn, &file->insns, list) { 345 + if (insn->type != INSN_CALL) 346 + continue; 347 + 348 + rela = find_rela_by_dest_range(insn->sec, insn->offset, 349 + insn->len); 350 + if (!rela) { 351 + dest_off = insn->offset + insn->len + insn->immediate; 352 + insn->call_dest = find_symbol_by_offset(insn->sec, 353 + dest_off); 354 + if (!insn->call_dest) { 355 + WARN_FUNC("can't find call dest symbol at offset 0x%lx", 356 + insn->sec, insn->offset, dest_off); 357 + return -1; 358 + } 359 + } else if (rela->sym->type == STT_SECTION) { 360 + insn->call_dest = find_symbol_by_offset(rela->sym->sec, 361 + rela->addend+4); 362 + if (!insn->call_dest || 363 + insn->call_dest->type != STT_FUNC) { 364 + WARN_FUNC("can't find call dest symbol at %s+0x%x", 365 + insn->sec, insn->offset, 366 + rela->sym->sec->name, 367 + rela->addend + 4); 368 + return -1; 369 + } 370 + } else 371 + insn->call_dest = rela->sym; 372 + } 373 + 374 + return 0; 375 + } 376 + 377 + /* 378 + * The .alternatives section requires some extra special care, over and above 379 + * what other special sections require: 380 + * 381 + * 1. Because alternatives are patched in-place, we need to insert a fake jump 382 + * instruction at the end so that validate_branch() skips all the original 383 + * replaced instructions when validating the new instruction path. 384 + * 385 + * 2. An added wrinkle is that the new instruction length might be zero. In 386 + * that case the old instructions are replaced with noops. We simulate that 387 + * by creating a fake jump as the only new instruction. 388 + * 389 + * 3. In some cases, the alternative section includes an instruction which 390 + * conditionally jumps to the _end_ of the entry. We have to modify these 391 + * jumps' destinations to point back to .text rather than the end of the 392 + * entry in .altinstr_replacement. 393 + * 394 + * 4. It has been requested that we don't validate the !POPCNT feature path 395 + * which is a "very very small percentage of machines". 396 + */ 397 + static int handle_group_alt(struct objtool_file *file, 398 + struct special_alt *special_alt, 399 + struct instruction *orig_insn, 400 + struct instruction **new_insn) 401 + { 402 + struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; 403 + unsigned long dest_off; 404 + 405 + last_orig_insn = NULL; 406 + insn = orig_insn; 407 + list_for_each_entry_from(insn, &file->insns, list) { 408 + if (insn->sec != special_alt->orig_sec || 409 + insn->offset >= special_alt->orig_off + special_alt->orig_len) 410 + break; 411 + 412 + if (special_alt->skip_orig) 413 + insn->type = INSN_NOP; 414 + 415 + insn->alt_group = true; 416 + last_orig_insn = insn; 417 + } 418 + 419 + if (list_is_last(&last_orig_insn->list, &file->insns) || 420 + list_next_entry(last_orig_insn, list)->sec != special_alt->orig_sec) { 421 + WARN("%s: don't know how to handle alternatives at end of section", 422 + special_alt->orig_sec->name); 423 + return -1; 424 + } 425 + 426 + fake_jump = malloc(sizeof(*fake_jump)); 427 + if (!fake_jump) { 428 + WARN("malloc failed"); 429 + return -1; 430 + } 431 + memset(fake_jump, 0, sizeof(*fake_jump)); 432 + INIT_LIST_HEAD(&fake_jump->alts); 433 + fake_jump->sec = special_alt->new_sec; 434 + fake_jump->offset = -1; 435 + fake_jump->type = INSN_JUMP_UNCONDITIONAL; 436 + fake_jump->jump_dest = list_next_entry(last_orig_insn, list); 437 + 438 + if (!special_alt->new_len) { 439 + *new_insn = fake_jump; 440 + return 0; 441 + } 442 + 443 + last_new_insn = NULL; 444 + insn = *new_insn; 445 + list_for_each_entry_from(insn, &file->insns, list) { 446 + if (insn->sec != special_alt->new_sec || 447 + insn->offset >= special_alt->new_off + special_alt->new_len) 448 + break; 449 + 450 + last_new_insn = insn; 451 + 452 + if (insn->type != INSN_JUMP_CONDITIONAL && 453 + insn->type != INSN_JUMP_UNCONDITIONAL) 454 + continue; 455 + 456 + if (!insn->immediate) 457 + continue; 458 + 459 + dest_off = insn->offset + insn->len + insn->immediate; 460 + if (dest_off == special_alt->new_off + special_alt->new_len) 461 + insn->jump_dest = fake_jump; 462 + 463 + if (!insn->jump_dest) { 464 + WARN_FUNC("can't find alternative jump destination", 465 + insn->sec, insn->offset); 466 + return -1; 467 + } 468 + } 469 + 470 + if (!last_new_insn) { 471 + WARN_FUNC("can't find last new alternative instruction", 472 + special_alt->new_sec, special_alt->new_off); 473 + return -1; 474 + } 475 + 476 + list_add(&fake_jump->list, &last_new_insn->list); 477 + 478 + return 0; 479 + } 480 + 481 + /* 482 + * A jump table entry can either convert a nop to a jump or a jump to a nop. 483 + * If the original instruction is a jump, make the alt entry an effective nop 484 + * by just skipping the original instruction. 485 + */ 486 + static int handle_jump_alt(struct objtool_file *file, 487 + struct special_alt *special_alt, 488 + struct instruction *orig_insn, 489 + struct instruction **new_insn) 490 + { 491 + if (orig_insn->type == INSN_NOP) 492 + return 0; 493 + 494 + if (orig_insn->type != INSN_JUMP_UNCONDITIONAL) { 495 + WARN_FUNC("unsupported instruction at jump label", 496 + orig_insn->sec, orig_insn->offset); 497 + return -1; 498 + } 499 + 500 + *new_insn = list_next_entry(orig_insn, list); 501 + return 0; 502 + } 503 + 504 + /* 505 + * Read all the special sections which have alternate instructions which can be 506 + * patched in or redirected to at runtime. Each instruction having alternate 507 + * instruction(s) has them added to its insn->alts list, which will be 508 + * traversed in validate_branch(). 509 + */ 510 + static int get_special_section_alts(struct objtool_file *file) 511 + { 512 + struct list_head special_alts; 513 + struct instruction *orig_insn, *new_insn; 514 + struct special_alt *special_alt, *tmp; 515 + struct alternative *alt; 516 + int ret; 517 + 518 + ret = special_get_alts(file->elf, &special_alts); 519 + if (ret) 520 + return ret; 521 + 522 + list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { 523 + alt = malloc(sizeof(*alt)); 524 + if (!alt) { 525 + WARN("malloc failed"); 526 + ret = -1; 527 + goto out; 528 + } 529 + 530 + orig_insn = find_instruction(file, special_alt->orig_sec, 531 + special_alt->orig_off); 532 + if (!orig_insn) { 533 + WARN_FUNC("special: can't find orig instruction", 534 + special_alt->orig_sec, special_alt->orig_off); 535 + ret = -1; 536 + goto out; 537 + } 538 + 539 + new_insn = NULL; 540 + if (!special_alt->group || special_alt->new_len) { 541 + new_insn = find_instruction(file, special_alt->new_sec, 542 + special_alt->new_off); 543 + if (!new_insn) { 544 + WARN_FUNC("special: can't find new instruction", 545 + special_alt->new_sec, 546 + special_alt->new_off); 547 + ret = -1; 548 + goto out; 549 + } 550 + } 551 + 552 + if (special_alt->group) { 553 + ret = handle_group_alt(file, special_alt, orig_insn, 554 + &new_insn); 555 + if (ret) 556 + goto out; 557 + } else if (special_alt->jump_or_nop) { 558 + ret = handle_jump_alt(file, special_alt, orig_insn, 559 + &new_insn); 560 + if (ret) 561 + goto out; 562 + } 563 + 564 + alt->insn = new_insn; 565 + list_add_tail(&alt->list, &orig_insn->alts); 566 + 567 + list_del(&special_alt->list); 568 + free(special_alt); 569 + } 570 + 571 + out: 572 + return ret; 573 + } 574 + 575 + /* 576 + * For some switch statements, gcc generates a jump table in the .rodata 577 + * section which contains a list of addresses within the function to jump to. 578 + * This finds these jump tables and adds them to the insn->alts lists. 579 + */ 580 + static int get_switch_alts(struct objtool_file *file) 581 + { 582 + struct instruction *insn, *alt_insn; 583 + struct rela *rodata_rela, *rela; 584 + struct section *rodata; 585 + struct symbol *func; 586 + struct alternative *alt; 587 + 588 + list_for_each_entry(insn, &file->insns, list) { 589 + if (insn->type != INSN_JUMP_DYNAMIC) 590 + continue; 591 + 592 + rodata_rela = find_rela_by_dest_range(insn->sec, insn->offset, 593 + insn->len); 594 + if (!rodata_rela || strcmp(rodata_rela->sym->name, ".rodata")) 595 + continue; 596 + 597 + rodata = find_section_by_name(file->elf, ".rodata"); 598 + if (!rodata || !rodata->rela) 599 + continue; 600 + 601 + /* common case: jmpq *[addr](,%rax,8) */ 602 + rela = find_rela_by_dest(rodata, rodata_rela->addend); 603 + 604 + /* rare case: jmpq *[addr](%rip) */ 605 + if (!rela) 606 + rela = find_rela_by_dest(rodata, 607 + rodata_rela->addend + 4); 608 + if (!rela) 609 + continue; 610 + 611 + func = find_containing_func(insn->sec, insn->offset); 612 + if (!func) { 613 + WARN_FUNC("can't find containing func", 614 + insn->sec, insn->offset); 615 + return -1; 616 + } 617 + 618 + list_for_each_entry_from(rela, &rodata->rela->relas, list) { 619 + if (rela->sym->sec != insn->sec || 620 + rela->addend <= func->offset || 621 + rela->addend >= func->offset + func->len) 622 + break; 623 + 624 + alt_insn = find_instruction(file, insn->sec, 625 + rela->addend); 626 + if (!alt_insn) { 627 + WARN("%s: can't find instruction at %s+0x%x", 628 + rodata->rela->name, insn->sec->name, 629 + rela->addend); 630 + return -1; 631 + } 632 + 633 + alt = malloc(sizeof(*alt)); 634 + if (!alt) { 635 + WARN("malloc failed"); 636 + return -1; 637 + } 638 + 639 + alt->insn = alt_insn; 640 + list_add_tail(&alt->list, &insn->alts); 641 + } 642 + } 643 + 644 + return 0; 645 + } 646 + 647 + static int decode_sections(struct objtool_file *file) 648 + { 649 + int ret; 650 + 651 + ret = decode_instructions(file); 652 + if (ret) 653 + return ret; 654 + 655 + get_ignores(file); 656 + 657 + ret = get_jump_destinations(file); 658 + if (ret) 659 + return ret; 660 + 661 + ret = get_call_destinations(file); 662 + if (ret) 663 + return ret; 664 + 665 + ret = get_special_section_alts(file); 666 + if (ret) 667 + return ret; 668 + 669 + ret = get_switch_alts(file); 670 + if (ret) 671 + return ret; 672 + 673 + return 0; 674 + } 675 + 676 + static bool is_fentry_call(struct instruction *insn) 677 + { 678 + if (insn->type == INSN_CALL && 679 + insn->call_dest->type == STT_NOTYPE && 680 + !strcmp(insn->call_dest->name, "__fentry__")) 681 + return true; 682 + 683 + return false; 684 + } 685 + 686 + static bool has_modified_stack_frame(struct instruction *insn) 687 + { 688 + return (insn->state & STATE_FP_SAVED) || 689 + (insn->state & STATE_FP_SETUP); 690 + } 691 + 692 + static bool has_valid_stack_frame(struct instruction *insn) 693 + { 694 + return (insn->state & STATE_FP_SAVED) && 695 + (insn->state & STATE_FP_SETUP); 696 + } 697 + 698 + /* 699 + * Follow the branch starting at the given instruction, and recursively follow 700 + * any other branches (jumps). Meanwhile, track the frame pointer state at 701 + * each instruction and validate all the rules described in 702 + * tools/objtool/Documentation/stack-validation.txt. 703 + */ 704 + static int validate_branch(struct objtool_file *file, 705 + struct instruction *first, unsigned char first_state) 706 + { 707 + struct alternative *alt; 708 + struct instruction *insn; 709 + struct section *sec; 710 + unsigned char state; 711 + int ret, warnings = 0; 712 + 713 + insn = first; 714 + sec = insn->sec; 715 + state = first_state; 716 + 717 + if (insn->alt_group && list_empty(&insn->alts)) { 718 + WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", 719 + sec, insn->offset); 720 + warnings++; 721 + } 722 + 723 + while (1) { 724 + if (insn->visited) { 725 + if (insn->state != state) { 726 + WARN_FUNC("frame pointer state mismatch", 727 + sec, insn->offset); 728 + warnings++; 729 + } 730 + 731 + return warnings; 732 + } 733 + 734 + /* 735 + * Catch a rare case where a noreturn function falls through to 736 + * the next function. 737 + */ 738 + if (is_fentry_call(insn) && (state & STATE_FENTRY)) 739 + return warnings; 740 + 741 + insn->visited = true; 742 + insn->state = state; 743 + 744 + list_for_each_entry(alt, &insn->alts, list) { 745 + ret = validate_branch(file, alt->insn, state); 746 + warnings += ret; 747 + } 748 + 749 + switch (insn->type) { 750 + 751 + case INSN_FP_SAVE: 752 + if (!nofp) { 753 + if (state & STATE_FP_SAVED) { 754 + WARN_FUNC("duplicate frame pointer save", 755 + sec, insn->offset); 756 + warnings++; 757 + } 758 + state |= STATE_FP_SAVED; 759 + } 760 + break; 761 + 762 + case INSN_FP_SETUP: 763 + if (!nofp) { 764 + if (state & STATE_FP_SETUP) { 765 + WARN_FUNC("duplicate frame pointer setup", 766 + sec, insn->offset); 767 + warnings++; 768 + } 769 + state |= STATE_FP_SETUP; 770 + } 771 + break; 772 + 773 + case INSN_FP_RESTORE: 774 + if (!nofp) { 775 + if (has_valid_stack_frame(insn)) 776 + state &= ~STATE_FP_SETUP; 777 + 778 + state &= ~STATE_FP_SAVED; 779 + } 780 + break; 781 + 782 + case INSN_RETURN: 783 + if (!nofp && has_modified_stack_frame(insn)) { 784 + WARN_FUNC("return without frame pointer restore", 785 + sec, insn->offset); 786 + warnings++; 787 + } 788 + return warnings; 789 + 790 + case INSN_CALL: 791 + if (is_fentry_call(insn)) { 792 + state |= STATE_FENTRY; 793 + break; 794 + } 795 + 796 + if (dead_end_function(file, insn->call_dest)) 797 + return warnings; 798 + 799 + /* fallthrough */ 800 + case INSN_CALL_DYNAMIC: 801 + if (!nofp && !has_valid_stack_frame(insn)) { 802 + WARN_FUNC("call without frame pointer save/setup", 803 + sec, insn->offset); 804 + warnings++; 805 + } 806 + break; 807 + 808 + case INSN_JUMP_CONDITIONAL: 809 + case INSN_JUMP_UNCONDITIONAL: 810 + if (insn->jump_dest) { 811 + ret = validate_branch(file, insn->jump_dest, 812 + state); 813 + warnings += ret; 814 + } else if (has_modified_stack_frame(insn)) { 815 + WARN_FUNC("sibling call from callable instruction with changed frame pointer", 816 + sec, insn->offset); 817 + warnings++; 818 + } /* else it's a sibling call */ 819 + 820 + if (insn->type == INSN_JUMP_UNCONDITIONAL) 821 + return warnings; 822 + 823 + break; 824 + 825 + case INSN_JUMP_DYNAMIC: 826 + if (list_empty(&insn->alts) && 827 + has_modified_stack_frame(insn)) { 828 + WARN_FUNC("sibling call from callable instruction with changed frame pointer", 829 + sec, insn->offset); 830 + warnings++; 831 + } 832 + 833 + return warnings; 834 + 835 + case INSN_BUG: 836 + return warnings; 837 + 838 + default: 839 + break; 840 + } 841 + 842 + insn = list_next_entry(insn, list); 843 + 844 + if (&insn->list == &file->insns || insn->sec != sec) { 845 + WARN("%s: unexpected end of section", sec->name); 846 + warnings++; 847 + return warnings; 848 + } 849 + } 850 + 851 + return warnings; 852 + } 853 + 854 + static bool is_gcov_insn(struct instruction *insn) 855 + { 856 + struct rela *rela; 857 + struct section *sec; 858 + struct symbol *sym; 859 + unsigned long offset; 860 + 861 + rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); 862 + if (!rela) 863 + return false; 864 + 865 + if (rela->sym->type != STT_SECTION) 866 + return false; 867 + 868 + sec = rela->sym->sec; 869 + offset = rela->addend + insn->offset + insn->len - rela->offset; 870 + 871 + list_for_each_entry(sym, &sec->symbols, list) { 872 + if (sym->type != STT_OBJECT) 873 + continue; 874 + 875 + if (offset >= sym->offset && offset < sym->offset + sym->len) 876 + return (!memcmp(sym->name, "__gcov0.", 8)); 877 + } 878 + 879 + return false; 880 + } 881 + 882 + static bool is_kasan_insn(struct instruction *insn) 883 + { 884 + return (insn->type == INSN_CALL && 885 + !strcmp(insn->call_dest->name, "__asan_handle_no_return")); 886 + } 887 + 888 + static bool is_ubsan_insn(struct instruction *insn) 889 + { 890 + return (insn->type == INSN_CALL && 891 + !strcmp(insn->call_dest->name, 892 + "__ubsan_handle_builtin_unreachable")); 893 + } 894 + 895 + static bool ignore_unreachable_insn(struct instruction *insn, 896 + unsigned long func_end) 897 + { 898 + int i; 899 + 900 + if (insn->type == INSN_NOP) 901 + return true; 902 + 903 + if (is_gcov_insn(insn)) 904 + return true; 905 + 906 + /* 907 + * Check if this (or a subsequent) instruction is related to 908 + * CONFIG_UBSAN or CONFIG_KASAN. 909 + * 910 + * End the search at 5 instructions to avoid going into the weeds. 911 + */ 912 + for (i = 0; i < 5; i++) { 913 + 914 + if (is_kasan_insn(insn) || is_ubsan_insn(insn)) 915 + return true; 916 + 917 + if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { 918 + insn = insn->jump_dest; 919 + continue; 920 + } 921 + 922 + if (insn->offset + insn->len >= func_end) 923 + break; 924 + insn = list_next_entry(insn, list); 925 + } 926 + 927 + return false; 928 + } 929 + 930 + static int validate_functions(struct objtool_file *file) 931 + { 932 + struct section *sec; 933 + struct symbol *func; 934 + struct instruction *insn; 935 + unsigned long func_end; 936 + int ret, warnings = 0; 937 + 938 + list_for_each_entry(sec, &file->elf->sections, list) { 939 + list_for_each_entry(func, &sec->symbols, list) { 940 + if (func->type != STT_FUNC) 941 + continue; 942 + 943 + insn = find_instruction(file, sec, func->offset); 944 + if (!insn) { 945 + WARN("%s(): can't find starting instruction", 946 + func->name); 947 + warnings++; 948 + continue; 949 + } 950 + 951 + ret = validate_branch(file, insn, 0); 952 + warnings += ret; 953 + } 954 + } 955 + 956 + list_for_each_entry(sec, &file->elf->sections, list) { 957 + list_for_each_entry(func, &sec->symbols, list) { 958 + if (func->type != STT_FUNC) 959 + continue; 960 + 961 + insn = find_instruction(file, sec, func->offset); 962 + if (!insn) 963 + continue; 964 + 965 + func_end = func->offset + func->len; 966 + 967 + list_for_each_entry_from(insn, &file->insns, list) { 968 + if (insn->sec != func->sec || 969 + insn->offset >= func_end) 970 + break; 971 + 972 + if (insn->visited) 973 + continue; 974 + 975 + if (!ignore_unreachable_insn(insn, func_end)) { 976 + WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); 977 + warnings++; 978 + } 979 + 980 + insn->visited = true; 981 + } 982 + } 983 + } 984 + 985 + return warnings; 986 + } 987 + 988 + static int validate_uncallable_instructions(struct objtool_file *file) 989 + { 990 + struct instruction *insn; 991 + int warnings = 0; 992 + 993 + list_for_each_entry(insn, &file->insns, list) { 994 + if (!insn->visited && insn->type == INSN_RETURN) { 995 + WARN_FUNC("return instruction outside of a callable function", 996 + insn->sec, insn->offset); 997 + warnings++; 998 + } 999 + } 1000 + 1001 + return warnings; 1002 + } 1003 + 1004 + static void cleanup(struct objtool_file *file) 1005 + { 1006 + struct instruction *insn, *tmpinsn; 1007 + struct alternative *alt, *tmpalt; 1008 + 1009 + list_for_each_entry_safe(insn, tmpinsn, &file->insns, list) { 1010 + list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) { 1011 + list_del(&alt->list); 1012 + free(alt); 1013 + } 1014 + list_del(&insn->list); 1015 + free(insn); 1016 + } 1017 + elf_close(file->elf); 1018 + } 1019 + 1020 + const char * const check_usage[] = { 1021 + "objtool check [<options>] file.o", 1022 + NULL, 1023 + }; 1024 + 1025 + int cmd_check(int argc, const char **argv) 1026 + { 1027 + struct objtool_file file; 1028 + int ret, warnings = 0; 1029 + 1030 + const struct option options[] = { 1031 + OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"), 1032 + OPT_END(), 1033 + }; 1034 + 1035 + argc = parse_options(argc, argv, options, check_usage, 0); 1036 + 1037 + if (argc != 1) 1038 + usage_with_options(check_usage, options); 1039 + 1040 + objname = argv[0]; 1041 + 1042 + file.elf = elf_open(objname); 1043 + if (!file.elf) { 1044 + fprintf(stderr, "error reading elf file %s\n", objname); 1045 + return 1; 1046 + } 1047 + 1048 + INIT_LIST_HEAD(&file.insns); 1049 + 1050 + ret = decode_sections(&file); 1051 + if (ret < 0) 1052 + goto out; 1053 + warnings += ret; 1054 + 1055 + ret = validate_functions(&file); 1056 + if (ret < 0) 1057 + goto out; 1058 + warnings += ret; 1059 + 1060 + ret = validate_uncallable_instructions(&file); 1061 + if (ret < 0) 1062 + goto out; 1063 + warnings += ret; 1064 + 1065 + out: 1066 + cleanup(&file); 1067 + 1068 + /* ignore warnings for now until we get all the code cleaned up */ 1069 + if (ret || warnings) 1070 + return 0; 1071 + return 0; 1072 + }
+22
tools/objtool/builtin.h
··· 1 + /* 2 + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 2 7 + * of the License, or (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + #ifndef _BUILTIN_H 18 + #define _BUILTIN_H 19 + 20 + extern int cmd_check(int argc, const char **argv); 21 + 22 + #endif /* _BUILTIN_H */
+403
tools/objtool/elf.c
··· 1 + /* 2 + * elf.c - ELF access library 3 + * 4 + * Adapted from kpatch (https://github.com/dynup/kpatch): 5 + * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com> 6 + * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com> 7 + * 8 + * This program is free software; you can redistribute it and/or 9 + * modify it under the terms of the GNU General Public License 10 + * as published by the Free Software Foundation; either version 2 11 + * of the License, or (at your option) any later version. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 20 + */ 21 + 22 + #include <sys/types.h> 23 + #include <sys/stat.h> 24 + #include <fcntl.h> 25 + #include <stdio.h> 26 + #include <stdlib.h> 27 + #include <string.h> 28 + #include <unistd.h> 29 + 30 + #include "elf.h" 31 + #include "warn.h" 32 + 33 + struct section *find_section_by_name(struct elf *elf, const char *name) 34 + { 35 + struct section *sec; 36 + 37 + list_for_each_entry(sec, &elf->sections, list) 38 + if (!strcmp(sec->name, name)) 39 + return sec; 40 + 41 + return NULL; 42 + } 43 + 44 + static struct section *find_section_by_index(struct elf *elf, 45 + unsigned int idx) 46 + { 47 + struct section *sec; 48 + 49 + list_for_each_entry(sec, &elf->sections, list) 50 + if (sec->idx == idx) 51 + return sec; 52 + 53 + return NULL; 54 + } 55 + 56 + static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx) 57 + { 58 + struct section *sec; 59 + struct symbol *sym; 60 + 61 + list_for_each_entry(sec, &elf->sections, list) 62 + list_for_each_entry(sym, &sec->symbols, list) 63 + if (sym->idx == idx) 64 + return sym; 65 + 66 + return NULL; 67 + } 68 + 69 + struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) 70 + { 71 + struct symbol *sym; 72 + 73 + list_for_each_entry(sym, &sec->symbols, list) 74 + if (sym->type != STT_SECTION && 75 + sym->offset == offset) 76 + return sym; 77 + 78 + return NULL; 79 + } 80 + 81 + struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, 82 + unsigned int len) 83 + { 84 + struct rela *rela; 85 + 86 + if (!sec->rela) 87 + return NULL; 88 + 89 + list_for_each_entry(rela, &sec->rela->relas, list) 90 + if (rela->offset >= offset && rela->offset < offset + len) 91 + return rela; 92 + 93 + return NULL; 94 + } 95 + 96 + struct rela *find_rela_by_dest(struct section *sec, unsigned long offset) 97 + { 98 + return find_rela_by_dest_range(sec, offset, 1); 99 + } 100 + 101 + struct symbol *find_containing_func(struct section *sec, unsigned long offset) 102 + { 103 + struct symbol *func; 104 + 105 + list_for_each_entry(func, &sec->symbols, list) 106 + if (func->type == STT_FUNC && offset >= func->offset && 107 + offset < func->offset + func->len) 108 + return func; 109 + 110 + return NULL; 111 + } 112 + 113 + static int read_sections(struct elf *elf) 114 + { 115 + Elf_Scn *s = NULL; 116 + struct section *sec; 117 + size_t shstrndx, sections_nr; 118 + int i; 119 + 120 + if (elf_getshdrnum(elf->elf, &sections_nr)) { 121 + perror("elf_getshdrnum"); 122 + return -1; 123 + } 124 + 125 + if (elf_getshdrstrndx(elf->elf, &shstrndx)) { 126 + perror("elf_getshdrstrndx"); 127 + return -1; 128 + } 129 + 130 + for (i = 0; i < sections_nr; i++) { 131 + sec = malloc(sizeof(*sec)); 132 + if (!sec) { 133 + perror("malloc"); 134 + return -1; 135 + } 136 + memset(sec, 0, sizeof(*sec)); 137 + 138 + INIT_LIST_HEAD(&sec->symbols); 139 + INIT_LIST_HEAD(&sec->relas); 140 + 141 + list_add_tail(&sec->list, &elf->sections); 142 + 143 + s = elf_getscn(elf->elf, i); 144 + if (!s) { 145 + perror("elf_getscn"); 146 + return -1; 147 + } 148 + 149 + sec->idx = elf_ndxscn(s); 150 + 151 + if (!gelf_getshdr(s, &sec->sh)) { 152 + perror("gelf_getshdr"); 153 + return -1; 154 + } 155 + 156 + sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); 157 + if (!sec->name) { 158 + perror("elf_strptr"); 159 + return -1; 160 + } 161 + 162 + sec->elf_data = elf_getdata(s, NULL); 163 + if (!sec->elf_data) { 164 + perror("elf_getdata"); 165 + return -1; 166 + } 167 + 168 + if (sec->elf_data->d_off != 0 || 169 + sec->elf_data->d_size != sec->sh.sh_size) { 170 + WARN("unexpected data attributes for %s", sec->name); 171 + return -1; 172 + } 173 + 174 + sec->data = (unsigned long)sec->elf_data->d_buf; 175 + sec->len = sec->elf_data->d_size; 176 + } 177 + 178 + /* sanity check, one more call to elf_nextscn() should return NULL */ 179 + if (elf_nextscn(elf->elf, s)) { 180 + WARN("section entry mismatch"); 181 + return -1; 182 + } 183 + 184 + return 0; 185 + } 186 + 187 + static int read_symbols(struct elf *elf) 188 + { 189 + struct section *symtab; 190 + struct symbol *sym; 191 + struct list_head *entry, *tmp; 192 + int symbols_nr, i; 193 + 194 + symtab = find_section_by_name(elf, ".symtab"); 195 + if (!symtab) { 196 + WARN("missing symbol table"); 197 + return -1; 198 + } 199 + 200 + symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize; 201 + 202 + for (i = 0; i < symbols_nr; i++) { 203 + sym = malloc(sizeof(*sym)); 204 + if (!sym) { 205 + perror("malloc"); 206 + return -1; 207 + } 208 + memset(sym, 0, sizeof(*sym)); 209 + 210 + sym->idx = i; 211 + 212 + if (!gelf_getsym(symtab->elf_data, i, &sym->sym)) { 213 + perror("gelf_getsym"); 214 + goto err; 215 + } 216 + 217 + sym->name = elf_strptr(elf->elf, symtab->sh.sh_link, 218 + sym->sym.st_name); 219 + if (!sym->name) { 220 + perror("elf_strptr"); 221 + goto err; 222 + } 223 + 224 + sym->type = GELF_ST_TYPE(sym->sym.st_info); 225 + sym->bind = GELF_ST_BIND(sym->sym.st_info); 226 + 227 + if (sym->sym.st_shndx > SHN_UNDEF && 228 + sym->sym.st_shndx < SHN_LORESERVE) { 229 + sym->sec = find_section_by_index(elf, 230 + sym->sym.st_shndx); 231 + if (!sym->sec) { 232 + WARN("couldn't find section for symbol %s", 233 + sym->name); 234 + goto err; 235 + } 236 + if (sym->type == STT_SECTION) { 237 + sym->name = sym->sec->name; 238 + sym->sec->sym = sym; 239 + } 240 + } else 241 + sym->sec = find_section_by_index(elf, 0); 242 + 243 + sym->offset = sym->sym.st_value; 244 + sym->len = sym->sym.st_size; 245 + 246 + /* sorted insert into a per-section list */ 247 + entry = &sym->sec->symbols; 248 + list_for_each_prev(tmp, &sym->sec->symbols) { 249 + struct symbol *s; 250 + 251 + s = list_entry(tmp, struct symbol, list); 252 + 253 + if (sym->offset > s->offset) { 254 + entry = tmp; 255 + break; 256 + } 257 + 258 + if (sym->offset == s->offset && sym->len >= s->len) { 259 + entry = tmp; 260 + break; 261 + } 262 + } 263 + list_add(&sym->list, entry); 264 + } 265 + 266 + return 0; 267 + 268 + err: 269 + free(sym); 270 + return -1; 271 + } 272 + 273 + static int read_relas(struct elf *elf) 274 + { 275 + struct section *sec; 276 + struct rela *rela; 277 + int i; 278 + unsigned int symndx; 279 + 280 + list_for_each_entry(sec, &elf->sections, list) { 281 + if (sec->sh.sh_type != SHT_RELA) 282 + continue; 283 + 284 + sec->base = find_section_by_name(elf, sec->name + 5); 285 + if (!sec->base) { 286 + WARN("can't find base section for rela section %s", 287 + sec->name); 288 + return -1; 289 + } 290 + 291 + sec->base->rela = sec; 292 + 293 + for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) { 294 + rela = malloc(sizeof(*rela)); 295 + if (!rela) { 296 + perror("malloc"); 297 + return -1; 298 + } 299 + memset(rela, 0, sizeof(*rela)); 300 + 301 + list_add_tail(&rela->list, &sec->relas); 302 + 303 + if (!gelf_getrela(sec->elf_data, i, &rela->rela)) { 304 + perror("gelf_getrela"); 305 + return -1; 306 + } 307 + 308 + rela->type = GELF_R_TYPE(rela->rela.r_info); 309 + rela->addend = rela->rela.r_addend; 310 + rela->offset = rela->rela.r_offset; 311 + symndx = GELF_R_SYM(rela->rela.r_info); 312 + rela->sym = find_symbol_by_index(elf, symndx); 313 + if (!rela->sym) { 314 + WARN("can't find rela entry symbol %d for %s", 315 + symndx, sec->name); 316 + return -1; 317 + } 318 + } 319 + } 320 + 321 + return 0; 322 + } 323 + 324 + struct elf *elf_open(const char *name) 325 + { 326 + struct elf *elf; 327 + 328 + elf_version(EV_CURRENT); 329 + 330 + elf = malloc(sizeof(*elf)); 331 + if (!elf) { 332 + perror("malloc"); 333 + return NULL; 334 + } 335 + memset(elf, 0, sizeof(*elf)); 336 + 337 + INIT_LIST_HEAD(&elf->sections); 338 + 339 + elf->name = strdup(name); 340 + if (!elf->name) { 341 + perror("strdup"); 342 + goto err; 343 + } 344 + 345 + elf->fd = open(name, O_RDONLY); 346 + if (elf->fd == -1) { 347 + perror("open"); 348 + goto err; 349 + } 350 + 351 + elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); 352 + if (!elf->elf) { 353 + perror("elf_begin"); 354 + goto err; 355 + } 356 + 357 + if (!gelf_getehdr(elf->elf, &elf->ehdr)) { 358 + perror("gelf_getehdr"); 359 + goto err; 360 + } 361 + 362 + if (read_sections(elf)) 363 + goto err; 364 + 365 + if (read_symbols(elf)) 366 + goto err; 367 + 368 + if (read_relas(elf)) 369 + goto err; 370 + 371 + return elf; 372 + 373 + err: 374 + elf_close(elf); 375 + return NULL; 376 + } 377 + 378 + void elf_close(struct elf *elf) 379 + { 380 + struct section *sec, *tmpsec; 381 + struct symbol *sym, *tmpsym; 382 + struct rela *rela, *tmprela; 383 + 384 + list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) { 385 + list_for_each_entry_safe(sym, tmpsym, &sec->symbols, list) { 386 + list_del(&sym->list); 387 + free(sym); 388 + } 389 + list_for_each_entry_safe(rela, tmprela, &sec->relas, list) { 390 + list_del(&rela->list); 391 + free(rela); 392 + } 393 + list_del(&sec->list); 394 + free(sec); 395 + } 396 + if (elf->name) 397 + free(elf->name); 398 + if (elf->fd > 0) 399 + close(elf->fd); 400 + if (elf->elf) 401 + elf_end(elf->elf); 402 + free(elf); 403 + }
+79
tools/objtool/elf.h
··· 1 + /* 2 + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 2 7 + * of the License, or (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #ifndef _OBJTOOL_ELF_H 19 + #define _OBJTOOL_ELF_H 20 + 21 + #include <stdio.h> 22 + #include <gelf.h> 23 + #include <linux/list.h> 24 + 25 + struct section { 26 + struct list_head list; 27 + GElf_Shdr sh; 28 + struct list_head symbols; 29 + struct list_head relas; 30 + struct section *base, *rela; 31 + struct symbol *sym; 32 + Elf_Data *elf_data; 33 + char *name; 34 + int idx; 35 + unsigned long data; 36 + unsigned int len; 37 + }; 38 + 39 + struct symbol { 40 + struct list_head list; 41 + GElf_Sym sym; 42 + struct section *sec; 43 + char *name; 44 + int idx; 45 + unsigned char bind, type; 46 + unsigned long offset; 47 + unsigned int len; 48 + }; 49 + 50 + struct rela { 51 + struct list_head list; 52 + GElf_Rela rela; 53 + struct symbol *sym; 54 + unsigned int type; 55 + int offset; 56 + int addend; 57 + }; 58 + 59 + struct elf { 60 + Elf *elf; 61 + GElf_Ehdr ehdr; 62 + int fd; 63 + char *name; 64 + struct list_head sections; 65 + }; 66 + 67 + 68 + struct elf *elf_open(const char *name); 69 + struct section *find_section_by_name(struct elf *elf, const char *name); 70 + struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); 71 + struct rela *find_rela_by_dest(struct section *sec, unsigned long offset); 72 + struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, 73 + unsigned int len); 74 + struct symbol *find_containing_func(struct section *sec, unsigned long offset); 75 + void elf_close(struct elf *elf); 76 + 77 + 78 + 79 + #endif /* _OBJTOOL_ELF_H */
+136
tools/objtool/objtool.c
··· 1 + /* 2 + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 2 7 + * of the License, or (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + /* 19 + * objtool: 20 + * 21 + * The 'check' subcmd analyzes every .o file and ensures the validity of its 22 + * stack trace metadata. It enforces a set of rules on asm code and C inline 23 + * assembly code so that stack traces can be reliable. 24 + * 25 + * For more information, see tools/objtool/Documentation/stack-validation.txt. 26 + */ 27 + 28 + #include <stdio.h> 29 + #include <stdbool.h> 30 + #include <string.h> 31 + #include <stdlib.h> 32 + #include <subcmd/exec-cmd.h> 33 + #include <subcmd/pager.h> 34 + 35 + #include "builtin.h" 36 + 37 + #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 38 + 39 + struct cmd_struct { 40 + const char *name; 41 + int (*fn)(int, const char **); 42 + const char *help; 43 + }; 44 + 45 + static const char objtool_usage_string[] = 46 + "objtool [OPTIONS] COMMAND [ARGS]"; 47 + 48 + static struct cmd_struct objtool_cmds[] = { 49 + {"check", cmd_check, "Perform stack metadata validation on an object file" }, 50 + }; 51 + 52 + bool help; 53 + 54 + static void cmd_usage(void) 55 + { 56 + unsigned int i, longest = 0; 57 + 58 + printf("\n usage: %s\n\n", objtool_usage_string); 59 + 60 + for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 61 + if (longest < strlen(objtool_cmds[i].name)) 62 + longest = strlen(objtool_cmds[i].name); 63 + } 64 + 65 + puts(" Commands:"); 66 + for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 67 + printf(" %-*s ", longest, objtool_cmds[i].name); 68 + puts(objtool_cmds[i].help); 69 + } 70 + 71 + printf("\n"); 72 + 73 + exit(1); 74 + } 75 + 76 + static void handle_options(int *argc, const char ***argv) 77 + { 78 + while (*argc > 0) { 79 + const char *cmd = (*argv)[0]; 80 + 81 + if (cmd[0] != '-') 82 + break; 83 + 84 + if (!strcmp(cmd, "--help") || !strcmp(cmd, "-h")) { 85 + help = true; 86 + break; 87 + } else { 88 + fprintf(stderr, "Unknown option: %s\n", cmd); 89 + fprintf(stderr, "\n Usage: %s\n", 90 + objtool_usage_string); 91 + exit(1); 92 + } 93 + 94 + (*argv)++; 95 + (*argc)--; 96 + } 97 + } 98 + 99 + static void handle_internal_command(int argc, const char **argv) 100 + { 101 + const char *cmd = argv[0]; 102 + unsigned int i, ret; 103 + 104 + for (i = 0; i < ARRAY_SIZE(objtool_cmds); i++) { 105 + struct cmd_struct *p = objtool_cmds+i; 106 + 107 + if (strcmp(p->name, cmd)) 108 + continue; 109 + 110 + ret = p->fn(argc, argv); 111 + 112 + exit(ret); 113 + } 114 + 115 + cmd_usage(); 116 + } 117 + 118 + int main(int argc, const char **argv) 119 + { 120 + static const char *UNUSED = "OBJTOOL_NOT_IMPLEMENTED"; 121 + 122 + /* libsubcmd init */ 123 + exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); 124 + pager_init(UNUSED); 125 + 126 + argv++; 127 + argc--; 128 + handle_options(&argc, &argv); 129 + 130 + if (!argc || help) 131 + cmd_usage(); 132 + 133 + handle_internal_command(argc, argv); 134 + 135 + return 0; 136 + }
+193
tools/objtool/special.c
··· 1 + /* 2 + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 2 7 + * of the License, or (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + /* 19 + * This file reads all the special sections which have alternate instructions 20 + * which can be patched in or redirected to at runtime. 21 + */ 22 + 23 + #include <stdlib.h> 24 + #include <string.h> 25 + 26 + #include "special.h" 27 + #include "warn.h" 28 + 29 + #define EX_ENTRY_SIZE 12 30 + #define EX_ORIG_OFFSET 0 31 + #define EX_NEW_OFFSET 4 32 + 33 + #define JUMP_ENTRY_SIZE 24 34 + #define JUMP_ORIG_OFFSET 0 35 + #define JUMP_NEW_OFFSET 8 36 + 37 + #define ALT_ENTRY_SIZE 13 38 + #define ALT_ORIG_OFFSET 0 39 + #define ALT_NEW_OFFSET 4 40 + #define ALT_FEATURE_OFFSET 8 41 + #define ALT_ORIG_LEN_OFFSET 10 42 + #define ALT_NEW_LEN_OFFSET 11 43 + 44 + #define X86_FEATURE_POPCNT (4*32+23) 45 + 46 + struct special_entry { 47 + const char *sec; 48 + bool group, jump_or_nop; 49 + unsigned char size, orig, new; 50 + unsigned char orig_len, new_len; /* group only */ 51 + unsigned char feature; /* ALTERNATIVE macro CPU feature */ 52 + }; 53 + 54 + struct special_entry entries[] = { 55 + { 56 + .sec = ".altinstructions", 57 + .group = true, 58 + .size = ALT_ENTRY_SIZE, 59 + .orig = ALT_ORIG_OFFSET, 60 + .orig_len = ALT_ORIG_LEN_OFFSET, 61 + .new = ALT_NEW_OFFSET, 62 + .new_len = ALT_NEW_LEN_OFFSET, 63 + .feature = ALT_FEATURE_OFFSET, 64 + }, 65 + { 66 + .sec = "__jump_table", 67 + .jump_or_nop = true, 68 + .size = JUMP_ENTRY_SIZE, 69 + .orig = JUMP_ORIG_OFFSET, 70 + .new = JUMP_NEW_OFFSET, 71 + }, 72 + { 73 + .sec = "__ex_table", 74 + .size = EX_ENTRY_SIZE, 75 + .orig = EX_ORIG_OFFSET, 76 + .new = EX_NEW_OFFSET, 77 + }, 78 + {}, 79 + }; 80 + 81 + static int get_alt_entry(struct elf *elf, struct special_entry *entry, 82 + struct section *sec, int idx, 83 + struct special_alt *alt) 84 + { 85 + struct rela *orig_rela, *new_rela; 86 + unsigned long offset; 87 + 88 + offset = idx * entry->size; 89 + 90 + alt->group = entry->group; 91 + alt->jump_or_nop = entry->jump_or_nop; 92 + 93 + if (alt->group) { 94 + alt->orig_len = *(unsigned char *)(sec->data + offset + 95 + entry->orig_len); 96 + alt->new_len = *(unsigned char *)(sec->data + offset + 97 + entry->new_len); 98 + } 99 + 100 + if (entry->feature) { 101 + unsigned short feature; 102 + 103 + feature = *(unsigned short *)(sec->data + offset + 104 + entry->feature); 105 + 106 + /* 107 + * It has been requested that we don't validate the !POPCNT 108 + * feature path which is a "very very small percentage of 109 + * machines". 110 + */ 111 + if (feature == X86_FEATURE_POPCNT) 112 + alt->skip_orig = true; 113 + } 114 + 115 + orig_rela = find_rela_by_dest(sec, offset + entry->orig); 116 + if (!orig_rela) { 117 + WARN_FUNC("can't find orig rela", sec, offset + entry->orig); 118 + return -1; 119 + } 120 + if (orig_rela->sym->type != STT_SECTION) { 121 + WARN_FUNC("don't know how to handle non-section rela symbol %s", 122 + sec, offset + entry->orig, orig_rela->sym->name); 123 + return -1; 124 + } 125 + 126 + alt->orig_sec = orig_rela->sym->sec; 127 + alt->orig_off = orig_rela->addend; 128 + 129 + if (!entry->group || alt->new_len) { 130 + new_rela = find_rela_by_dest(sec, offset + entry->new); 131 + if (!new_rela) { 132 + WARN_FUNC("can't find new rela", 133 + sec, offset + entry->new); 134 + return -1; 135 + } 136 + 137 + alt->new_sec = new_rela->sym->sec; 138 + alt->new_off = (unsigned int)new_rela->addend; 139 + 140 + /* _ASM_EXTABLE_EX hack */ 141 + if (alt->new_off >= 0x7ffffff0) 142 + alt->new_off -= 0x7ffffff0; 143 + } 144 + 145 + return 0; 146 + } 147 + 148 + /* 149 + * Read all the special sections and create a list of special_alt structs which 150 + * describe all the alternate instructions which can be patched in or 151 + * redirected to at runtime. 152 + */ 153 + int special_get_alts(struct elf *elf, struct list_head *alts) 154 + { 155 + struct special_entry *entry; 156 + struct section *sec; 157 + unsigned int nr_entries; 158 + struct special_alt *alt; 159 + int idx, ret; 160 + 161 + INIT_LIST_HEAD(alts); 162 + 163 + for (entry = entries; entry->sec; entry++) { 164 + sec = find_section_by_name(elf, entry->sec); 165 + if (!sec) 166 + continue; 167 + 168 + if (sec->len % entry->size != 0) { 169 + WARN("%s size not a multiple of %d", 170 + sec->name, entry->size); 171 + return -1; 172 + } 173 + 174 + nr_entries = sec->len / entry->size; 175 + 176 + for (idx = 0; idx < nr_entries; idx++) { 177 + alt = malloc(sizeof(*alt)); 178 + if (!alt) { 179 + WARN("malloc failed"); 180 + return -1; 181 + } 182 + memset(alt, 0, sizeof(*alt)); 183 + 184 + ret = get_alt_entry(elf, entry, sec, idx, alt); 185 + if (ret) 186 + return ret; 187 + 188 + list_add_tail(&alt->list, alts); 189 + } 190 + } 191 + 192 + return 0; 193 + }
+42
tools/objtool/special.h
··· 1 + /* 2 + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 2 7 + * of the License, or (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #ifndef _SPECIAL_H 19 + #define _SPECIAL_H 20 + 21 + #include <stdbool.h> 22 + #include "elf.h" 23 + 24 + struct special_alt { 25 + struct list_head list; 26 + 27 + bool group; 28 + bool skip_orig; 29 + bool jump_or_nop; 30 + 31 + struct section *orig_sec; 32 + unsigned long orig_off; 33 + 34 + struct section *new_sec; 35 + unsigned long new_off; 36 + 37 + unsigned int orig_len, new_len; /* group only */ 38 + }; 39 + 40 + int special_get_alts(struct elf *elf, struct list_head *alts); 41 + 42 + #endif /* _SPECIAL_H */
+60
tools/objtool/warn.h
··· 1 + /* 2 + * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public License 6 + * as published by the Free Software Foundation; either version 2 7 + * of the License, or (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 + */ 17 + 18 + #ifndef _WARN_H 19 + #define _WARN_H 20 + 21 + extern const char *objname; 22 + 23 + static inline char *offstr(struct section *sec, unsigned long offset) 24 + { 25 + struct symbol *func; 26 + char *name, *str; 27 + unsigned long name_off; 28 + 29 + func = find_containing_func(sec, offset); 30 + if (func) { 31 + name = func->name; 32 + name_off = offset - func->offset; 33 + } else { 34 + name = sec->name; 35 + name_off = offset; 36 + } 37 + 38 + str = malloc(strlen(name) + 20); 39 + 40 + if (func) 41 + sprintf(str, "%s()+0x%lx", name, name_off); 42 + else 43 + sprintf(str, "%s+0x%lx", name, name_off); 44 + 45 + return str; 46 + } 47 + 48 + #define WARN(format, ...) \ 49 + fprintf(stderr, \ 50 + "%s: warning: objtool: " format "\n", \ 51 + objname, ##__VA_ARGS__) 52 + 53 + #define WARN_FUNC(format, sec, offset, ...) \ 54 + ({ \ 55 + char *_str = offstr(sec, offset); \ 56 + WARN("%s: " format, _str, ##__VA_ARGS__); \ 57 + free(_str); \ 58 + }) 59 + 60 + #endif /* _WARN_H */