aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJosh Poimboeuf <jpoimboe@redhat.com>2016-02-28 23:22:41 -0500
committerIngo Molnar <mingo@kernel.org>2016-02-29 02:35:12 -0500
commit442f04c34a1a467759d024a1d2c1df0f744dcb06 (patch)
tree0da60b38cb2476a5d9bedd24d67f3fde8624e151 /tools
parent87aaff2ae09036cf699fde20dfd52ce7d3c8eabe (diff)
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>
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile14
-rw-r--r--tools/objtool/.gitignore2
-rw-r--r--tools/objtool/Build13
-rw-r--r--tools/objtool/Documentation/stack-validation.txt342
-rw-r--r--tools/objtool/Makefile60
-rw-r--r--tools/objtool/arch.h44
-rw-r--r--tools/objtool/arch/x86/Build12
-rw-r--r--tools/objtool/arch/x86/decode.c172
-rw-r--r--tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk387
-rw-r--r--tools/objtool/arch/x86/insn/inat.c97
-rw-r--r--tools/objtool/arch/x86/insn/inat.h221
-rw-r--r--tools/objtool/arch/x86/insn/inat_types.h29
-rw-r--r--tools/objtool/arch/x86/insn/insn.c594
-rw-r--r--tools/objtool/arch/x86/insn/insn.h201
-rw-r--r--tools/objtool/arch/x86/insn/x86-opcode-map.txt984
-rw-r--r--tools/objtool/builtin-check.c1072
-rw-r--r--tools/objtool/builtin.h22
-rw-r--r--tools/objtool/elf.c403
-rw-r--r--tools/objtool/elf.h79
-rw-r--r--tools/objtool/objtool.c136
-rw-r--r--tools/objtool/special.c193
-rw-r--r--tools/objtool/special.h42
-rw-r--r--tools/objtool/warn.h60
23 files changed, 5173 insertions, 6 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 6339f6ac3ccb..cc2a37d975d6 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -20,6 +20,7 @@ help:
20 @echo ' perf - Linux performance measurement and analysis tool' 20 @echo ' perf - Linux performance measurement and analysis tool'
21 @echo ' selftests - various kernel selftests' 21 @echo ' selftests - various kernel selftests'
22 @echo ' spi - spi tools' 22 @echo ' spi - spi tools'
23 @echo ' objtool - an ELF object analysis tool'
23 @echo ' tmon - thermal monitoring and tuning tool' 24 @echo ' tmon - thermal monitoring and tuning tool'
24 @echo ' turbostat - Intel CPU idle stats and freq reporting tool' 25 @echo ' turbostat - Intel CPU idle stats and freq reporting tool'
25 @echo ' usb - USB testing tools' 26 @echo ' usb - USB testing tools'
@@ -53,7 +54,7 @@ acpi: FORCE
53cpupower: FORCE 54cpupower: FORCE
54 $(call descend,power/$@) 55 $(call descend,power/$@)
55 56
56cgroup firewire hv guest spi usb virtio vm net iio: FORCE 57cgroup firewire hv guest spi usb virtio vm net iio objtool: FORCE
57 $(call descend,$@) 58 $(call descend,$@)
58 59
59liblockdep: FORCE 60liblockdep: FORCE
@@ -85,7 +86,7 @@ freefall: FORCE
85all: acpi cgroup cpupower hv firewire lguest \ 86all: acpi cgroup cpupower hv firewire lguest \
86 perf selftests turbostat usb \ 87 perf selftests turbostat usb \
87 virtio vm net x86_energy_perf_policy \ 88 virtio vm net x86_energy_perf_policy \
88 tmon freefall 89 tmon freefall objtool
89 90
90acpi_install: 91acpi_install:
91 $(call descend,power/$(@:_install=),install) 92 $(call descend,power/$(@:_install=),install)
@@ -93,7 +94,7 @@ acpi_install:
93cpupower_install: 94cpupower_install:
94 $(call descend,power/$(@:_install=),install) 95 $(call descend,power/$(@:_install=),install)
95 96
96cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install: 97cgroup_install firewire_install hv_install lguest_install perf_install usb_install virtio_install vm_install net_install objtool_install:
97 $(call descend,$(@:_install=),install) 98 $(call descend,$(@:_install=),install)
98 99
99selftests_install: 100selftests_install:
@@ -111,7 +112,7 @@ freefall_install:
111install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \ 112install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
112 perf_install selftests_install turbostat_install usb_install \ 113 perf_install selftests_install turbostat_install usb_install \
113 virtio_install vm_install net_install x86_energy_perf_policy_install \ 114 virtio_install vm_install net_install x86_energy_perf_policy_install \
114 tmon_install freefall_install 115 tmon_install freefall_install objtool_install
115 116
116acpi_clean: 117acpi_clean:
117 $(call descend,power/acpi,clean) 118 $(call descend,power/acpi,clean)
@@ -119,7 +120,7 @@ acpi_clean:
119cpupower_clean: 120cpupower_clean:
120 $(call descend,power/cpupower,clean) 121 $(call descend,power/cpupower,clean)
121 122
122cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean: 123cgroup_clean hv_clean firewire_clean lguest_clean spi_clean usb_clean virtio_clean vm_clean net_clean iio_clean objtool_clean:
123 $(call descend,$(@:_clean=),clean) 124 $(call descend,$(@:_clean=),clean)
124 125
125liblockdep_clean: 126liblockdep_clean:
@@ -155,6 +156,7 @@ build_clean:
155clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \ 156clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean lguest_clean \
156 perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \ 157 perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
157 vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ 158 vm_clean net_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
158 freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean 159 freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
160 objtool_clean
159 161
160.PHONY: FORCE 162.PHONY: FORCE
diff --git a/tools/objtool/.gitignore b/tools/objtool/.gitignore
new file mode 100644
index 000000000000..a0b3128bb31f
--- /dev/null
+++ b/tools/objtool/.gitignore
@@ -0,0 +1,2 @@
1arch/x86/insn/inat-tables.c
2objtool
diff --git a/tools/objtool/Build b/tools/objtool/Build
new file mode 100644
index 000000000000..0e89258a3541
--- /dev/null
+++ b/tools/objtool/Build
@@ -0,0 +1,13 @@
1objtool-y += arch/$(ARCH)/
2objtool-y += builtin-check.o
3objtool-y += elf.o
4objtool-y += special.o
5objtool-y += objtool.o
6
7objtool-y += libstring.o
8
9CFLAGS += -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)
diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt
new file mode 100644
index 000000000000..5a95896105bc
--- /dev/null
+++ b/tools/objtool/Documentation/stack-validation.txt
@@ -0,0 +1,342 @@
1Compile-time stack metadata validation
2======================================
3
4
5Overview
6--------
7
8The kernel CONFIG_STACK_VALIDATION option enables a host tool named
9objtool which runs at compile time. It has a "check" subcommand which
10analyzes every .o file and ensures the validity of its stack metadata.
11It enforces a set of rules on asm code and C inline assembly code so
12that stack traces can be reliable.
13
14Currently it only checks frame pointer usage, but there are plans to add
15CFI validation for C files and CFI generation for asm files.
16
17For each function, it recursively follows all possible code paths and
18validates the correct frame pointer state at each instruction.
19
20It also follows code paths involving special sections, like
21.altinstructions, __jump_table, and __ex_table, which can add
22alternative execution paths to a given instruction (or set of
23instructions). Similarly, it knows how to follow switch statements, for
24which gcc sometimes uses jump tables.
25
26
27Why do we need stack metadata validation?
28-----------------------------------------
29
30Here are some of the benefits of validating stack metadata:
31
32a) 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
96b) 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
128c) 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
153Rules
154-----
155
156To achieve the validation, objtool enforces the following rules:
157
1581. 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
1672. 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
1743. 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
1844. 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
1965. 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
204Errors in .S files
205------------------
206
207If you're getting an error in a compiled .S file which you don't
208understand, first make sure that the affected code follows the above
209rules.
210
211Here are some examples of common warnings reported by objtool, what
212they mean, and suggestions for how to fix them.
213
214
2151. 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
2282. 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
2423. 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
2564. 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
2655. 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
2756. 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
2887. 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
299Errors in .c files
300------------------
301
302If you're getting an objtool error in a compiled .c file, chances are
303the file uses an asm() statement which has a "call" instruction. An
304asm() statement with a call instruction must declare the use of the
305stack 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
310Otherwise the stack frame may not get created before the call.
311
312Another 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
315Also see the above section for .S file errors for more information what
316the individual error messages mean.
317
318If the error doesn't seem to make sense, it could be a bug in objtool.
319Feel free to ask the objtool maintainer for help.
320
321
322Adding exceptions
323-----------------
324
325If you _really_ need objtool to ignore something, and are 100% sure
326that it won't affect kernel stack traces, you can tell objtool to
327ignore 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.
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
new file mode 100644
index 000000000000..c4f0713a1eb7
--- /dev/null
+++ b/tools/objtool/Makefile
@@ -0,0 +1,60 @@
1include ../scripts/Makefile.include
2
3ifndef ($(ARCH))
4ARCH ?= $(shell uname -m)
5ifeq ($(ARCH),x86_64)
6ARCH := x86
7endif
8endif
9
10ifeq ($(srctree),)
11srctree := $(patsubst %/,%,$(dir $(shell pwd)))
12srctree := $(patsubst %/,%,$(dir $(srctree)))
13endif
14
15SUBCMD_SRCDIR = $(srctree)/tools/lib/subcmd/
16LIBSUBCMD = $(if $(OUTPUT),$(OUTPUT),$(SUBCMD_SRCDIR))libsubcmd.a
17
18OBJTOOL := $(OUTPUT)objtool
19OBJTOOL_IN := $(OBJTOOL)-in.o
20
21all: $(OBJTOOL)
22
23INCLUDES := -I$(srctree)/tools/include
24CFLAGS += -Wall -Werror $(EXTRA_WARNINGS) -fomit-frame-pointer -O2 $(INCLUDES)
25LDFLAGS += -lelf $(LIBSUBCMD)
26
27AWK = awk
28export srctree OUTPUT CFLAGS ARCH AWK
29include $(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
53clean: $(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
58FORCE:
59
60.PHONY: clean FORCE
diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h
new file mode 100644
index 000000000000..f7350fcedc70
--- /dev/null
+++ b/tools/objtool/arch.h
@@ -0,0 +1,44 @@
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
39int 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 */
diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build
new file mode 100644
index 000000000000..debbdb0b5c43
--- /dev/null
+++ b/tools/objtool/arch/x86/Build
@@ -0,0 +1,12 @@
1objtool-y += decode.o
2
3inat_tables_script = arch/x86/insn/gen-insn-attr-x86.awk
4inat_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
12CFLAGS_decode.o += -I$(OUTPUT)arch/x86/insn
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
new file mode 100644
index 000000000000..c0c0b265e88e
--- /dev/null
+++ b/tools/objtool/arch/x86/decode.c
@@ -0,0 +1,172 @@
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
30static 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
43int 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}
diff --git a/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk b/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk
new file mode 100644
index 000000000000..093a892026f9
--- /dev/null
+++ b/tools/objtool/arch/x86/insn/gen-insn-attr-x86.awk
@@ -0,0 +1,387 @@
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
8function 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
15function 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
26BEGIN {
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
102function semantic_error(msg) {
103 print "Semantic error at " NR ": " msg > "/dev/stderr"
104 exit 1
105}
106
107function debug(msg) {
108 print "DEBUG: " msg
109}
110
111function 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
156function 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
225function 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.
235function 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
356END {
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
diff --git a/tools/objtool/arch/x86/insn/inat.c b/tools/objtool/arch/x86/insn/inat.c
new file mode 100644
index 000000000000..e4bf28e6f4c7
--- /dev/null
+++ b/tools/objtool/arch/x86/insn/inat.c
@@ -0,0 +1,97 @@
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 */
27insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode)
28{
29 return inat_primary_table[opcode];
30}
31
32int 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
40insn_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
59insn_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
79insn_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
diff --git a/tools/objtool/arch/x86/insn/inat.h b/tools/objtool/arch/x86/insn/inat.h
new file mode 100644
index 000000000000..611645e903a8
--- /dev/null
+++ b/tools/objtool/arch/x86/insn/inat.h
@@ -0,0 +1,221 @@
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 */
99extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode);
100extern int inat_get_last_prefix_id(insn_byte_t last_pfx);
101extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode,
102 int lpfx_id,
103 insn_attr_t esc_attr);
104extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm,
105 int lpfx_id,
106 insn_attr_t esc_attr);
107extern 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 */
112static 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
118static inline int inat_is_address_size_prefix(insn_attr_t attr)
119{
120 return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ;
121}
122
123static inline int inat_is_operand_size_prefix(insn_attr_t attr)
124{
125 return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ;
126}
127
128static inline int inat_is_rex_prefix(insn_attr_t attr)
129{
130 return (attr & INAT_PFX_MASK) == INAT_PFX_REX;
131}
132
133static 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
141static 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
147static inline int inat_is_vex3_prefix(insn_attr_t attr)
148{
149 return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3;
150}
151
152static inline int inat_is_escape(insn_attr_t attr)
153{
154 return attr & INAT_ESC_MASK;
155}
156
157static inline int inat_escape_id(insn_attr_t attr)
158{
159 return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS;
160}
161
162static inline int inat_is_group(insn_attr_t attr)
163{
164 return attr & INAT_GRP_MASK;
165}
166
167static inline int inat_group_id(insn_attr_t attr)
168{
169 return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS;
170}
171
172static inline int inat_group_common_attribute(insn_attr_t attr)
173{
174 return attr & ~INAT_GRP_MASK;
175}
176
177static inline int inat_has_immediate(insn_attr_t attr)
178{
179 return attr & INAT_IMM_MASK;
180}
181
182static inline int inat_immediate_size(insn_attr_t attr)
183{
184 return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS;
185}
186
187static inline int inat_has_modrm(insn_attr_t attr)
188{
189 return attr & INAT_MODRM;
190}
191
192static inline int inat_is_force64(insn_attr_t attr)
193{
194 return attr & INAT_FORCE64;
195}
196
197static inline int inat_has_second_immediate(insn_attr_t attr)
198{
199 return attr & INAT_SCNDIMM;
200}
201
202static inline int inat_has_moffset(insn_attr_t attr)
203{
204 return attr & INAT_MOFFSET;
205}
206
207static inline int inat_has_variant(insn_attr_t attr)
208{
209 return attr & INAT_VARIANT;
210}
211
212static inline int inat_accept_vex(insn_attr_t attr)
213{
214 return attr & INAT_VEXOK;
215}
216
217static inline int inat_must_vex(insn_attr_t attr)
218{
219 return attr & INAT_VEXONLY;
220}
221#endif
diff --git a/tools/objtool/arch/x86/insn/inat_types.h b/tools/objtool/arch/x86/insn/inat_types.h
new file mode 100644
index 000000000000..cb3c20ce39cf
--- /dev/null
+++ b/tools/objtool/arch/x86/insn/inat_types.h
@@ -0,0 +1,29 @@
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 */
25typedef unsigned int insn_attr_t;
26typedef unsigned char insn_byte_t;
27typedef signed int insn_value_t;
28
29#endif
diff --git a/tools/objtool/arch/x86/insn/insn.c b/tools/objtool/arch/x86/insn/insn.c
new file mode 100644
index 000000000000..47314a64399c
--- /dev/null
+++ b/tools/objtool/arch/x86/insn/insn.c
@@ -0,0 +1,594 @@
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 */
53void 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 */
82void 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 }
115found:
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 }
184vex_end:
185 insn->vex_prefix.got = 1;
186
187 prefixes->got = 1;
188
189err_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 */
203void 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 */
239end:
240 opcode->got = 1;
241
242err_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 */
254void 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
280err_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 */
292int 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 */
314void 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
332err_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 */
345void 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 }
393out:
394 insn->displacement.got = 1;
395
396err_out:
397 return;
398}
399
400/* Decode moffset16/32/64. Return 0 if failed */
401static 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
425err_out:
426 return 0;
427}
428
429/* Decode imm v32(Iz). Return 0 if failed */
430static 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
448err_out:
449 return 0;
450}
451
452/* Decode imm v64(Iv/Ov), Return 0 if failed */
453static 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;
476err_out:
477 return 0;
478}
479
480/* Decode ptr16:16/32(Ap) */
481static 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;
503err_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 */
516void 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 }
572done:
573 insn->immediate.got = 1;
574
575err_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 */
586void 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}
diff --git a/tools/objtool/arch/x86/insn/insn.h b/tools/objtool/arch/x86/insn/insn.h
new file mode 100644
index 000000000000..dd12da0f4593
--- /dev/null
+++ b/tools/objtool/arch/x86/insn/insn.h
@@ -0,0 +1,201 @@
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
26struct 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
36struct 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
100extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64);
101extern void insn_get_prefixes(struct insn *insn);
102extern void insn_get_opcode(struct insn *insn);
103extern void insn_get_modrm(struct insn *insn);
104extern void insn_get_sib(struct insn *insn);
105extern void insn_get_displacement(struct insn *insn);
106extern void insn_get_immediate(struct insn *insn);
107extern void insn_get_length(struct insn *insn);
108
109/* Attribute will be determined after getting ModRM (for opcode groups) */
110static inline void insn_get_attribute(struct insn *insn)
111{
112 insn_get_modrm(insn);
113}
114
115/* Instruction uses RIP-relative addressing */
116extern int insn_rip_relative(struct insn *insn);
117
118/* Init insn for kernel text */
119static 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
129static 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 */
137static 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
143static 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
151static 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 */
160static 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 */
172static inline int insn_offset_rex_prefix(struct insn *insn)
173{
174 return insn->prefixes.nbytes;
175}
176static inline int insn_offset_vex_prefix(struct insn *insn)
177{
178 return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes;
179}
180static inline int insn_offset_opcode(struct insn *insn)
181{
182 return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes;
183}
184static inline int insn_offset_modrm(struct insn *insn)
185{
186 return insn_offset_opcode(insn) + insn->opcode.nbytes;
187}
188static inline int insn_offset_sib(struct insn *insn)
189{
190 return insn_offset_modrm(insn) + insn->modrm.nbytes;
191}
192static inline int insn_offset_displacement(struct insn *insn)
193{
194 return insn_offset_sib(insn) + insn->sib.nbytes;
195}
196static 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 */
diff --git a/tools/objtool/arch/x86/insn/x86-opcode-map.txt b/tools/objtool/arch/x86/insn/x86-opcode-map.txt
new file mode 100644
index 000000000000..d388de72eaca
--- /dev/null
+++ b/tools/objtool/arch/x86/insn/x86-opcode-map.txt
@@ -0,0 +1,984 @@
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
32Table: one byte opcode
33Referrer:
34AVXcode:
35# 0x00 - 0x0f
3600: ADD Eb,Gb
3701: ADD Ev,Gv
3802: ADD Gb,Eb
3903: ADD Gv,Ev
4004: ADD AL,Ib
4105: ADD rAX,Iz
4206: PUSH ES (i64)
4307: POP ES (i64)
4408: OR Eb,Gb
4509: OR Ev,Gv
460a: OR Gb,Eb
470b: OR Gv,Ev
480c: OR AL,Ib
490d: OR rAX,Iz
500e: PUSH CS (i64)
510f: escape # 2-byte escape
52# 0x10 - 0x1f
5310: ADC Eb,Gb
5411: ADC Ev,Gv
5512: ADC Gb,Eb
5613: ADC Gv,Ev
5714: ADC AL,Ib
5815: ADC rAX,Iz
5916: PUSH SS (i64)
6017: POP SS (i64)
6118: SBB Eb,Gb
6219: SBB Ev,Gv
631a: SBB Gb,Eb
641b: SBB Gv,Ev
651c: SBB AL,Ib
661d: SBB rAX,Iz
671e: PUSH DS (i64)
681f: POP DS (i64)
69# 0x20 - 0x2f
7020: AND Eb,Gb
7121: AND Ev,Gv
7222: AND Gb,Eb
7323: AND Gv,Ev
7424: AND AL,Ib
7525: AND rAx,Iz
7626: SEG=ES (Prefix)
7727: DAA (i64)
7828: SUB Eb,Gb
7929: SUB Ev,Gv
802a: SUB Gb,Eb
812b: SUB Gv,Ev
822c: SUB AL,Ib
832d: SUB rAX,Iz
842e: SEG=CS (Prefix)
852f: DAS (i64)
86# 0x30 - 0x3f
8730: XOR Eb,Gb
8831: XOR Ev,Gv
8932: XOR Gb,Eb
9033: XOR Gv,Ev
9134: XOR AL,Ib
9235: XOR rAX,Iz
9336: SEG=SS (Prefix)
9437: AAA (i64)
9538: CMP Eb,Gb
9639: CMP Ev,Gv
973a: CMP Gb,Eb
983b: CMP Gv,Ev
993c: CMP AL,Ib
1003d: CMP rAX,Iz
1013e: SEG=DS (Prefix)
1023f: AAS (i64)
103# 0x40 - 0x4f
10440: INC eAX (i64) | REX (o64)
10541: INC eCX (i64) | REX.B (o64)
10642: INC eDX (i64) | REX.X (o64)
10743: INC eBX (i64) | REX.XB (o64)
10844: INC eSP (i64) | REX.R (o64)
10945: INC eBP (i64) | REX.RB (o64)
11046: INC eSI (i64) | REX.RX (o64)
11147: INC eDI (i64) | REX.RXB (o64)
11248: DEC eAX (i64) | REX.W (o64)
11349: DEC eCX (i64) | REX.WB (o64)
1144a: DEC eDX (i64) | REX.WX (o64)
1154b: DEC eBX (i64) | REX.WXB (o64)
1164c: DEC eSP (i64) | REX.WR (o64)
1174d: DEC eBP (i64) | REX.WRB (o64)
1184e: DEC eSI (i64) | REX.WRX (o64)
1194f: DEC eDI (i64) | REX.WRXB (o64)
120# 0x50 - 0x5f
12150: PUSH rAX/r8 (d64)
12251: PUSH rCX/r9 (d64)
12352: PUSH rDX/r10 (d64)
12453: PUSH rBX/r11 (d64)
12554: PUSH rSP/r12 (d64)
12655: PUSH rBP/r13 (d64)
12756: PUSH rSI/r14 (d64)
12857: PUSH rDI/r15 (d64)
12958: POP rAX/r8 (d64)
13059: POP rCX/r9 (d64)
1315a: POP rDX/r10 (d64)
1325b: POP rBX/r11 (d64)
1335c: POP rSP/r12 (d64)
1345d: POP rBP/r13 (d64)
1355e: POP rSI/r14 (d64)
1365f: POP rDI/r15 (d64)
137# 0x60 - 0x6f
13860: PUSHA/PUSHAD (i64)
13961: POPA/POPAD (i64)
14062: BOUND Gv,Ma (i64)
14163: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64)
14264: SEG=FS (Prefix)
14365: SEG=GS (Prefix)
14466: Operand-Size (Prefix)
14567: Address-Size (Prefix)
14668: PUSH Iz (d64)
14769: IMUL Gv,Ev,Iz
1486a: PUSH Ib (d64)
1496b: IMUL Gv,Ev,Ib
1506c: INS/INSB Yb,DX
1516d: INS/INSW/INSD Yz,DX
1526e: OUTS/OUTSB DX,Xb
1536f: OUTS/OUTSW/OUTSD DX,Xz
154# 0x70 - 0x7f
15570: JO Jb
15671: JNO Jb
15772: JB/JNAE/JC Jb
15873: JNB/JAE/JNC Jb
15974: JZ/JE Jb
16075: JNZ/JNE Jb
16176: JBE/JNA Jb
16277: JNBE/JA Jb
16378: JS Jb
16479: JNS Jb
1657a: JP/JPE Jb
1667b: JNP/JPO Jb
1677c: JL/JNGE Jb
1687d: JNL/JGE Jb
1697e: JLE/JNG Jb
1707f: JNLE/JG Jb
171# 0x80 - 0x8f
17280: Grp1 Eb,Ib (1A)
17381: Grp1 Ev,Iz (1A)
17482: Grp1 Eb,Ib (1A),(i64)
17583: Grp1 Ev,Ib (1A)
17684: TEST Eb,Gb
17785: TEST Ev,Gv
17886: XCHG Eb,Gb
17987: XCHG Ev,Gv
18088: MOV Eb,Gb
18189: MOV Ev,Gv
1828a: MOV Gb,Eb
1838b: MOV Gv,Ev
1848c: MOV Ev,Sw
1858d: LEA Gv,M
1868e: MOV Sw,Ew
1878f: Grp1A (1A) | POP Ev (d64)
188# 0x90 - 0x9f
18990: NOP | PAUSE (F3) | XCHG r8,rAX
19091: XCHG rCX/r9,rAX
19192: XCHG rDX/r10,rAX
19293: XCHG rBX/r11,rAX
19394: XCHG rSP/r12,rAX
19495: XCHG rBP/r13,rAX
19596: XCHG rSI/r14,rAX
19697: XCHG rDI/r15,rAX
19798: CBW/CWDE/CDQE
19899: CWD/CDQ/CQO
1999a: CALLF Ap (i64)
2009b: FWAIT/WAIT
2019c: PUSHF/D/Q Fv (d64)
2029d: POPF/D/Q Fv (d64)
2039e: SAHF
2049f: LAHF
205# 0xa0 - 0xaf
206a0: MOV AL,Ob
207a1: MOV rAX,Ov
208a2: MOV Ob,AL
209a3: MOV Ov,rAX
210a4: MOVS/B Yb,Xb
211a5: MOVS/W/D/Q Yv,Xv
212a6: CMPS/B Xb,Yb
213a7: CMPS/W/D Xv,Yv
214a8: TEST AL,Ib
215a9: TEST rAX,Iz
216aa: STOS/B Yb,AL
217ab: STOS/W/D/Q Yv,rAX
218ac: LODS/B AL,Xb
219ad: LODS/W/D/Q rAX,Xv
220ae: 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
223af: SCAS/W/D/Q rAX,Yv
224# 0xb0 - 0xbf
225b0: MOV AL/R8L,Ib
226b1: MOV CL/R9L,Ib
227b2: MOV DL/R10L,Ib
228b3: MOV BL/R11L,Ib
229b4: MOV AH/R12L,Ib
230b5: MOV CH/R13L,Ib
231b6: MOV DH/R14L,Ib
232b7: MOV BH/R15L,Ib
233b8: MOV rAX/r8,Iv
234b9: MOV rCX/r9,Iv
235ba: MOV rDX/r10,Iv
236bb: MOV rBX/r11,Iv
237bc: MOV rSP/r12,Iv
238bd: MOV rBP/r13,Iv
239be: MOV rSI/r14,Iv
240bf: MOV rDI/r15,Iv
241# 0xc0 - 0xcf
242c0: Grp2 Eb,Ib (1A)
243c1: Grp2 Ev,Ib (1A)
244c2: RETN Iw (f64)
245c3: RETN
246c4: LES Gz,Mp (i64) | VEX+2byte (Prefix)
247c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix)
248c6: Grp11A Eb,Ib (1A)
249c7: Grp11B Ev,Iz (1A)
250c8: ENTER Iw,Ib
251c9: LEAVE (d64)
252ca: RETF Iw
253cb: RETF
254cc: INT3
255cd: INT Ib
256ce: INTO (i64)
257cf: IRET/D/Q
258# 0xd0 - 0xdf
259d0: Grp2 Eb,1 (1A)
260d1: Grp2 Ev,1 (1A)
261d2: Grp2 Eb,CL (1A)
262d3: Grp2 Ev,CL (1A)
263d4: AAM Ib (i64)
264d5: AAD Ib (i64)
265d6:
266d7: XLAT/XLATB
267d8: ESC
268d9: ESC
269da: ESC
270db: ESC
271dc: ESC
272dd: ESC
273de: ESC
274df: 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.
279e0: LOOPNE/LOOPNZ Jb (f64)
280e1: LOOPE/LOOPZ Jb (f64)
281e2: LOOP Jb (f64)
282e3: JrCXZ Jb (f64)
283e4: IN AL,Ib
284e5: IN eAX,Ib
285e6: OUT Ib,AL
286e7: 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.
291e8: CALL Jz (f64)
292e9: JMP-near Jz (f64)
293ea: JMP-far Ap (i64)
294eb: JMP-short Jb (f64)
295ec: IN AL,DX
296ed: IN eAX,DX
297ee: OUT DX,AL
298ef: OUT DX,eAX
299# 0xf0 - 0xff
300f0: LOCK (Prefix)
301f1:
302f2: REPNE (Prefix) | XACQUIRE (Prefix)
303f3: REP/REPE (Prefix) | XRELEASE (Prefix)
304f4: HLT
305f5: CMC
306f6: Grp3_1 Eb (1A)
307f7: Grp3_2 Ev (1A)
308f8: CLC
309f9: STC
310fa: CLI
311fb: STI
312fc: CLD
313fd: STD
314fe: Grp4 (1A)
315ff: Grp5 (1A)
316EndTable
317
318Table: 2-byte opcode (0x0f)
319Referrer: 2-byte escape
320AVXcode: 1
321# 0x0f 0x00-0x0f
32200: Grp6 (1A)
32301: Grp7 (1A)
32402: LAR Gv,Ew
32503: LSL Gv,Ew
32604:
32705: SYSCALL (o64)
32806: CLTS
32907: SYSRET (o64)
33008: INVD
33109: WBINVD
3320a:
3330b: UD2 (1B)
3340c:
335# AMD's prefetch group. Intel supports prefetchw(/1) only.
3360d: GrpP
3370e: FEMMS
338# 3DNow! uses the last imm byte as opcode extension.
3390f: 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
34610: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1)
34711: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1)
34812: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2)
34913: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1)
35014: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66)
35115: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66)
35216: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3)
35317: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1)
35418: Grp16 (1A)
35519:
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.
3601a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev
3611b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv
3621c:
3631d:
3641e:
3651f: NOP Ev
366# 0x0f 0x20-0x2f
36720: MOV Rd,Cd
36821: MOV Rd,Dd
36922: MOV Cd,Rd
37023: MOV Dd,Rd
37124:
37225:
37326:
37427:
37528: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66)
37629: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66)
3772a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1)
3782b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66)
3792c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1)
3802d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1)
3812e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1)
3822f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1)
383# 0x0f 0x30-0x3f
38430: WRMSR
38531: RDTSC
38632: RDMSR
38733: RDPMC
38834: SYSENTER
38935: SYSEXIT
39036:
39137: GETSEC
39238: escape # 3-byte escape 1
39339:
3943a: escape # 3-byte escape 2
3953b:
3963c:
3973d:
3983e:
3993f:
400# 0x0f 0x40-0x4f
40140: CMOVO Gv,Ev
40241: CMOVNO Gv,Ev
40342: CMOVB/C/NAE Gv,Ev
40443: CMOVAE/NB/NC Gv,Ev
40544: CMOVE/Z Gv,Ev
40645: CMOVNE/NZ Gv,Ev
40746: CMOVBE/NA Gv,Ev
40847: CMOVA/NBE Gv,Ev
40948: CMOVS Gv,Ev
41049: CMOVNS Gv,Ev
4114a: CMOVP/PE Gv,Ev
4124b: CMOVNP/PO Gv,Ev
4134c: CMOVL/NGE Gv,Ev
4144d: CMOVNL/GE Gv,Ev
4154e: CMOVLE/NG Gv,Ev
4164f: CMOVNLE/G Gv,Ev
417# 0x0f 0x50-0x5f
41850: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66)
41951: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1)
42052: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1)
42153: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1)
42254: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66)
42355: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66)
42456: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66)
42557: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66)
42658: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1)
42759: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1)
4285a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1)
4295b: vcvtdq2ps Vps,Wdq | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3)
4305c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1)
4315d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1)
4325e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1)
4335f: 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
43560: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1)
43661: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1)
43762: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1)
43863: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1)
43964: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1)
44065: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1)
44166: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1)
44267: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1)
44368: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1)
44469: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1)
4456a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1)
4466b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1)
4476c: vpunpcklqdq Vx,Hx,Wx (66),(v1)
4486d: vpunpckhqdq Vx,Hx,Wx (66),(v1)
4496e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1)
4506f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqu Vx,Wx (F3)
451# 0x0f 0x70-0x7f
45270: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1)
45371: Grp12 (1A)
45472: Grp13 (1A)
45573: Grp14 (1A)
45674: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1)
45775: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1)
45876: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1)
459# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX.
46077: emms | vzeroupper | vzeroall
46178: VMREAD Ey,Gy
46279: VMWRITE Gy,Ey
4637a:
4647b:
4657c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2)
4667d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2)
4677e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1)
4687f: 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).
47180: JO Jz (f64)
47281: JNO Jz (f64)
47382: JB/JC/JNAE Jz (f64)
47483: JAE/JNB/JNC Jz (f64)
47584: JE/JZ Jz (f64)
47685: JNE/JNZ Jz (f64)
47786: JBE/JNA Jz (f64)
47887: JA/JNBE Jz (f64)
47988: JS Jz (f64)
48089: JNS Jz (f64)
4818a: JP/JPE Jz (f64)
4828b: JNP/JPO Jz (f64)
4838c: JL/JNGE Jz (f64)
4848d: JNL/JGE Jz (f64)
4858e: JLE/JNG Jz (f64)
4868f: JNLE/JG Jz (f64)
487# 0x0f 0x90-0x9f
48890: SETO Eb
48991: SETNO Eb
49092: SETB/C/NAE Eb
49193: SETAE/NB/NC Eb
49294: SETE/Z Eb
49395: SETNE/NZ Eb
49496: SETBE/NA Eb
49597: SETA/NBE Eb
49698: SETS Eb
49799: SETNS Eb
4989a: SETP/PE Eb
4999b: SETNP/PO Eb
5009c: SETL/NGE Eb
5019d: SETNL/GE Eb
5029e: SETLE/NG Eb
5039f: SETNLE/G Eb
504# 0x0f 0xa0-0xaf
505a0: PUSH FS (d64)
506a1: POP FS (d64)
507a2: CPUID
508a3: BT Ev,Gv
509a4: SHLD Ev,Gv,Ib
510a5: SHLD Ev,Gv,CL
511a6: GrpPDLK
512a7: GrpRNG
513a8: PUSH GS (d64)
514a9: POP GS (d64)
515aa: RSM
516ab: BTS Ev,Gv
517ac: SHRD Ev,Gv,Ib
518ad: SHRD Ev,Gv,CL
519ae: Grp15 (1A),(1C)
520af: IMUL Gv,Ev
521# 0x0f 0xb0-0xbf
522b0: CMPXCHG Eb,Gb
523b1: CMPXCHG Ev,Gv
524b2: LSS Gv,Mp
525b3: BTR Ev,Gv
526b4: LFS Gv,Mp
527b5: LGS Gv,Mp
528b6: MOVZX Gv,Eb
529b7: MOVZX Gv,Ew
530b8: JMPE (!F3) | POPCNT Gv,Ev (F3)
531b9: Grp10 (1A)
532ba: Grp8 Ev,Ib (1A)
533bb: BTC Ev,Gv
534bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3)
535bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3)
536be: MOVSX Gv,Eb
537bf: MOVSX Gv,Ew
538# 0x0f 0xc0-0xcf
539c0: XADD Eb,Gb
540c1: XADD Ev,Gv
541c2: 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)
542c3: movnti My,Gy
543c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1)
544c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1)
545c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66)
546c7: Grp9 (1A)
547c8: BSWAP RAX/EAX/R8/R8D
548c9: BSWAP RCX/ECX/R9/R9D
549ca: BSWAP RDX/EDX/R10/R10D
550cb: BSWAP RBX/EBX/R11/R11D
551cc: BSWAP RSP/ESP/R12/R12D
552cd: BSWAP RBP/EBP/R13/R13D
553ce: BSWAP RSI/ESI/R14/R14D
554cf: BSWAP RDI/EDI/R15/R15D
555# 0x0f 0xd0-0xdf
556d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2)
557d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1)
558d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1)
559d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1)
560d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1)
561d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1)
562d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2)
563d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1)
564d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1)
565d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1)
566da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1)
567db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1)
568dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1)
569dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1)
570de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1)
571df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1)
572# 0x0f 0xe0-0xef
573e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1)
574e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1)
575e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1)
576e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1)
577e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1)
578e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1)
579e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtpd2dq Vx,Wpd (F2)
580e7: movntq Mq,Pq | vmovntdq Mx,Vx (66)
581e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1)
582e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1)
583ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1)
584eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1)
585ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1)
586ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1)
587ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1)
588ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1)
589# 0x0f 0xf0-0xff
590f0: vlddqu Vx,Mx (F2)
591f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1)
592f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1)
593f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1)
594f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1)
595f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1)
596f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1)
597f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1)
598f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1)
599f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1)
600fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1)
601fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1)
602fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1)
603fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1)
604fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1)
605ff:
606EndTable
607
608Table: 3-byte opcode 1 (0x0f 0x38)
609Referrer: 3-byte escape 1
610AVXcode: 2
611# 0x0f 0x38 0x00-0x0f
61200: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1)
61301: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1)
61402: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1)
61503: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1)
61604: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1)
61705: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1)
61806: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1)
61907: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1)
62008: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1)
62109: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1)
6220a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1)
6230b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1)
6240c: vpermilps Vx,Hx,Wx (66),(v)
6250d: vpermilpd Vx,Hx,Wx (66),(v)
6260e: vtestps Vx,Wx (66),(v)
6270f: vtestpd Vx,Wx (66),(v)
628# 0x0f 0x38 0x10-0x1f
62910: pblendvb Vdq,Wdq (66)
63011:
63112:
63213: vcvtph2ps Vx,Wx,Ib (66),(v)
63314: blendvps Vdq,Wdq (66)
63415: blendvpd Vdq,Wdq (66)
63516: vpermps Vqq,Hqq,Wqq (66),(v)
63617: vptest Vx,Wx (66)
63718: vbroadcastss Vx,Wd (66),(v)
63819: vbroadcastsd Vqq,Wq (66),(v)
6391a: vbroadcastf128 Vqq,Mdq (66),(v)
6401b:
6411c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1)
6421d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1)
6431e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1)
6441f:
645# 0x0f 0x38 0x20-0x2f
64620: vpmovsxbw Vx,Ux/Mq (66),(v1)
64721: vpmovsxbd Vx,Ux/Md (66),(v1)
64822: vpmovsxbq Vx,Ux/Mw (66),(v1)
64923: vpmovsxwd Vx,Ux/Mq (66),(v1)
65024: vpmovsxwq Vx,Ux/Md (66),(v1)
65125: vpmovsxdq Vx,Ux/Mq (66),(v1)
65226:
65327:
65428: vpmuldq Vx,Hx,Wx (66),(v1)
65529: vpcmpeqq Vx,Hx,Wx (66),(v1)
6562a: vmovntdqa Vx,Mx (66),(v1)
6572b: vpackusdw Vx,Hx,Wx (66),(v1)
6582c: vmaskmovps Vx,Hx,Mx (66),(v)
6592d: vmaskmovpd Vx,Hx,Mx (66),(v)
6602e: vmaskmovps Mx,Hx,Vx (66),(v)
6612f: vmaskmovpd Mx,Hx,Vx (66),(v)
662# 0x0f 0x38 0x30-0x3f
66330: vpmovzxbw Vx,Ux/Mq (66),(v1)
66431: vpmovzxbd Vx,Ux/Md (66),(v1)
66532: vpmovzxbq Vx,Ux/Mw (66),(v1)
66633: vpmovzxwd Vx,Ux/Mq (66),(v1)
66734: vpmovzxwq Vx,Ux/Md (66),(v1)
66835: vpmovzxdq Vx,Ux/Mq (66),(v1)
66936: vpermd Vqq,Hqq,Wqq (66),(v)
67037: vpcmpgtq Vx,Hx,Wx (66),(v1)
67138: vpminsb Vx,Hx,Wx (66),(v1)
67239: vpminsd Vx,Hx,Wx (66),(v1)
6733a: vpminuw Vx,Hx,Wx (66),(v1)
6743b: vpminud Vx,Hx,Wx (66),(v1)
6753c: vpmaxsb Vx,Hx,Wx (66),(v1)
6763d: vpmaxsd Vx,Hx,Wx (66),(v1)
6773e: vpmaxuw Vx,Hx,Wx (66),(v1)
6783f: vpmaxud Vx,Hx,Wx (66),(v1)
679# 0x0f 0x38 0x40-0x8f
68040: vpmulld Vx,Hx,Wx (66),(v1)
68141: vphminposuw Vdq,Wdq (66),(v1)
68242:
68343:
68444:
68545: vpsrlvd/q Vx,Hx,Wx (66),(v)
68646: vpsravd Vx,Hx,Wx (66),(v)
68747: vpsllvd/q Vx,Hx,Wx (66),(v)
688# Skip 0x48-0x57
68958: vpbroadcastd Vx,Wx (66),(v)
69059: vpbroadcastq Vx,Wx (66),(v)
6915a: vbroadcasti128 Vqq,Mdq (66),(v)
692# Skip 0x5b-0x77
69378: vpbroadcastb Vx,Wx (66),(v)
69479: vpbroadcastw Vx,Wx (66),(v)
695# Skip 0x7a-0x7f
69680: INVEPT Gy,Mdq (66)
69781: INVPID Gy,Mdq (66)
69882: INVPCID Gy,Mdq (66)
6998c: vpmaskmovd/q Vx,Hx,Mx (66),(v)
7008e: vpmaskmovd/q Mx,Vx,Hx (66),(v)
701# 0x0f 0x38 0x90-0xbf (FMA)
70290: vgatherdd/q Vx,Hx,Wx (66),(v)
70391: vgatherqd/q Vx,Hx,Wx (66),(v)
70492: vgatherdps/d Vx,Hx,Wx (66),(v)
70593: vgatherqps/d Vx,Hx,Wx (66),(v)
70694:
70795:
70896: vfmaddsub132ps/d Vx,Hx,Wx (66),(v)
70997: vfmsubadd132ps/d Vx,Hx,Wx (66),(v)
71098: vfmadd132ps/d Vx,Hx,Wx (66),(v)
71199: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
7129a: vfmsub132ps/d Vx,Hx,Wx (66),(v)
7139b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
7149c: vfnmadd132ps/d Vx,Hx,Wx (66),(v)
7159d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
7169e: vfnmsub132ps/d Vx,Hx,Wx (66),(v)
7179f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
718a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v)
719a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v)
720a8: vfmadd213ps/d Vx,Hx,Wx (66),(v)
721a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
722aa: vfmsub213ps/d Vx,Hx,Wx (66),(v)
723ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
724ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v)
725ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
726ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v)
727af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
728b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v)
729b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v)
730b8: vfmadd231ps/d Vx,Hx,Wx (66),(v)
731b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1)
732ba: vfmsub231ps/d Vx,Hx,Wx (66),(v)
733bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1)
734bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v)
735bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1)
736be: vfnmsub231ps/d Vx,Hx,Wx (66),(v)
737bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1)
738# 0x0f 0x38 0xc0-0xff
739c8: sha1nexte Vdq,Wdq
740c9: sha1msg1 Vdq,Wdq
741ca: sha1msg2 Vdq,Wdq
742cb: sha256rnds2 Vdq,Wdq
743cc: sha256msg1 Vdq,Wdq
744cd: sha256msg2 Vdq,Wdq
745db: VAESIMC Vdq,Wdq (66),(v1)
746dc: VAESENC Vdq,Hdq,Wdq (66),(v1)
747dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1)
748de: VAESDEC Vdq,Hdq,Wdq (66),(v1)
749df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1)
750f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2)
751f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2)
752f2: ANDN Gy,By,Ey (v)
753f3: Grp17 (1A)
754f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v)
755f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v)
756f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v)
757EndTable
758
759Table: 3-byte opcode 2 (0x0f 0x3a)
760Referrer: 3-byte escape 2
761AVXcode: 3
762# 0x0f 0x3a 0x00-0xff
76300: vpermq Vqq,Wqq,Ib (66),(v)
76401: vpermpd Vqq,Wqq,Ib (66),(v)
76502: vpblendd Vx,Hx,Wx,Ib (66),(v)
76603:
76704: vpermilps Vx,Wx,Ib (66),(v)
76805: vpermilpd Vx,Wx,Ib (66),(v)
76906: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v)
77007:
77108: vroundps Vx,Wx,Ib (66)
77209: vroundpd Vx,Wx,Ib (66)
7730a: vroundss Vss,Wss,Ib (66),(v1)
7740b: vroundsd Vsd,Wsd,Ib (66),(v1)
7750c: vblendps Vx,Hx,Wx,Ib (66)
7760d: vblendpd Vx,Hx,Wx,Ib (66)
7770e: vpblendw Vx,Hx,Wx,Ib (66),(v1)
7780f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1)
77914: vpextrb Rd/Mb,Vdq,Ib (66),(v1)
78015: vpextrw Rd/Mw,Vdq,Ib (66),(v1)
78116: vpextrd/q Ey,Vdq,Ib (66),(v1)
78217: vextractps Ed,Vdq,Ib (66),(v1)
78318: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v)
78419: vextractf128 Wdq,Vqq,Ib (66),(v)
7851d: vcvtps2ph Wx,Vx,Ib (66),(v)
78620: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1)
78721: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1)
78822: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1)
78938: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v)
79039: vextracti128 Wdq,Vqq,Ib (66),(v)
79140: vdpps Vx,Hx,Wx,Ib (66)
79241: vdppd Vdq,Hdq,Wdq,Ib (66),(v1)
79342: vmpsadbw Vx,Hx,Wx,Ib (66),(v1)
79444: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1)
79546: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v)
7964a: vblendvps Vx,Hx,Wx,Lx (66),(v)
7974b: vblendvpd Vx,Hx,Wx,Lx (66),(v)
7984c: vpblendvb Vx,Hx,Wx,Lx (66),(v1)
79960: vpcmpestrm Vdq,Wdq,Ib (66),(v1)
80061: vpcmpestri Vdq,Wdq,Ib (66),(v1)
80162: vpcmpistrm Vdq,Wdq,Ib (66),(v1)
80263: vpcmpistri Vdq,Wdq,Ib (66),(v1)
803cc: sha1rnds4 Vdq,Wdq,Ib
804df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1)
805f0: RORX Gy,Ey,Ib (F2),(v)
806EndTable
807
808GrpTable: Grp1
8090: ADD
8101: OR
8112: ADC
8123: SBB
8134: AND
8145: SUB
8156: XOR
8167: CMP
817EndTable
818
819GrpTable: Grp1A
8200: POP
821EndTable
822
823GrpTable: Grp2
8240: ROL
8251: ROR
8262: RCL
8273: RCR
8284: SHL/SAL
8295: SHR
8306:
8317: SAR
832EndTable
833
834GrpTable: Grp3_1
8350: TEST Eb,Ib
8361:
8372: NOT Eb
8383: NEG Eb
8394: MUL AL,Eb
8405: IMUL AL,Eb
8416: DIV AL,Eb
8427: IDIV AL,Eb
843EndTable
844
845GrpTable: Grp3_2
8460: TEST Ev,Iz
8471:
8482: NOT Ev
8493: NEG Ev
8504: MUL rAX,Ev
8515: IMUL rAX,Ev
8526: DIV rAX,Ev
8537: IDIV rAX,Ev
854EndTable
855
856GrpTable: Grp4
8570: INC Eb
8581: DEC Eb
859EndTable
860
861GrpTable: Grp5
8620: INC Ev
8631: DEC Ev
864# Note: "forced64" is Intel CPU behavior (see comment about CALL insn).
8652: CALLN Ev (f64)
8663: CALLF Ep
8674: JMPN Ev (f64)
8685: JMPF Mp
8696: PUSH Ev (d64)
8707:
871EndTable
872
873GrpTable: Grp6
8740: SLDT Rv/Mw
8751: STR Rv/Mw
8762: LLDT Ew
8773: LTR Ew
8784: VERR Ew
8795: VERW Ew
880EndTable
881
882GrpTable: Grp7
8830: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
8841: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B)
8852: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B)
8863: LIDT Ms
8874: SMSW Mw/Rv
8885: rdpkru (110),(11B) | wrpkru (111),(11B)
8896: LMSW Ew
8907: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B)
891EndTable
892
893GrpTable: Grp8
8944: BT
8955: BTS
8966: BTR
8977: BTC
898EndTable
899
900GrpTable: Grp9
9011: CMPXCHG8B/16B Mq/Mdq
9023: xrstors
9034: xsavec
9045: xsaves
9056: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B)
9067: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B)
907EndTable
908
909GrpTable: Grp10
910EndTable
911
912# Grp11A and Grp11B are expressed as Grp11 in Intel SDM
913GrpTable: Grp11A
9140: MOV Eb,Ib
9157: XABORT Ib (000),(11B)
916EndTable
917
918GrpTable: Grp11B
9190: MOV Eb,Iz
9207: XBEGIN Jz (000),(11B)
921EndTable
922
923GrpTable: Grp12
9242: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1)
9254: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1)
9266: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1)
927EndTable
928
929GrpTable: Grp13
9302: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1)
9314: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1)
9326: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1)
933EndTable
934
935GrpTable: Grp14
9362: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1)
9373: vpsrldq Hx,Ux,Ib (66),(11B),(v1)
9386: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1)
9397: vpslldq Hx,Ux,Ib (66),(11B),(v1)
940EndTable
941
942GrpTable: Grp15
9430: fxsave | RDFSBASE Ry (F3),(11B)
9441: fxstor | RDGSBASE Ry (F3),(11B)
9452: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B)
9463: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B)
9474: XSAVE
9485: XRSTOR | lfence (11B)
9496: XSAVEOPT | clwb (66) | mfence (11B)
9507: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B)
951EndTable
952
953GrpTable: Grp16
9540: prefetch NTA
9551: prefetch T0
9562: prefetch T1
9573: prefetch T2
958EndTable
959
960GrpTable: Grp17
9611: BLSR By,Ey (v)
9622: BLSMSK By,Ey (v)
9633: BLSI By,Ey (v)
964EndTable
965
966# AMD's Prefetch Group
967GrpTable: GrpP
9680: PREFETCH
9691: PREFETCHW
970EndTable
971
972GrpTable: GrpPDLK
9730: MONTMUL
9741: XSHA1
9752: XSHA2
976EndTable
977
978GrpTable: GrpRNG
9790: xstore-rng
9801: xcrypt-ecb
9812: xcrypt-cbc
9824: xcrypt-cfb
9835: xcrypt-ofb
984EndTable
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c
new file mode 100644
index 000000000000..f7e0ebac3fbe
--- /dev/null
+++ b/tools/objtool/builtin-check.c
@@ -0,0 +1,1072 @@
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
43struct 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
56struct alternative {
57 struct list_head list;
58 struct instruction *insn;
59};
60
61struct objtool_file {
62 struct elf *elf;
63 struct list_head insns;
64};
65
66const char *objname;
67static bool nofp;
68
69static 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 */
87static 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 */
125static 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 */
204static 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 */
249static 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 */
281static 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 */
338static 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 */
397static 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 */
486static 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 */
510static 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
571out:
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 */
580static 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
647static 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
676static 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
686static bool has_modified_stack_frame(struct instruction *insn)
687{
688 return (insn->state & STATE_FP_SAVED) ||
689 (insn->state & STATE_FP_SETUP);
690}
691
692static 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 */
704static 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
854static 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
882static 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
888static 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
895static 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
930static 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
988static 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
1004static 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
1020const char * const check_usage[] = {
1021 "objtool check [<options>] file.o",
1022 NULL,
1023};
1024
1025int 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
1065out:
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}
diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h
new file mode 100644
index 000000000000..34d2ba78a616
--- /dev/null
+++ b/tools/objtool/builtin.h
@@ -0,0 +1,22 @@
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
20extern int cmd_check(int argc, const char **argv);
21
22#endif /* _BUILTIN_H */
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
new file mode 100644
index 000000000000..d547e3f6e0ee
--- /dev/null
+++ b/tools/objtool/elf.c
@@ -0,0 +1,403 @@
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
33struct 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
44static 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
56static 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
69struct 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
81struct 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
96struct rela *find_rela_by_dest(struct section *sec, unsigned long offset)
97{
98 return find_rela_by_dest_range(sec, offset, 1);
99}
100
101struct 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
113static 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
187static 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
268err:
269 free(sym);
270 return -1;
271}
272
273static 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
324struct 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
373err:
374 elf_close(elf);
375 return NULL;
376}
377
378void 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}
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h
new file mode 100644
index 000000000000..66919de57e68
--- /dev/null
+++ b/tools/objtool/elf.h
@@ -0,0 +1,79 @@
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
25struct 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
39struct 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
50struct 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
59struct elf {
60 Elf *elf;
61 GElf_Ehdr ehdr;
62 int fd;
63 char *name;
64 struct list_head sections;
65};
66
67
68struct elf *elf_open(const char *name);
69struct section *find_section_by_name(struct elf *elf, const char *name);
70struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
71struct rela *find_rela_by_dest(struct section *sec, unsigned long offset);
72struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
73 unsigned int len);
74struct symbol *find_containing_func(struct section *sec, unsigned long offset);
75void elf_close(struct elf *elf);
76
77
78
79#endif /* _OBJTOOL_ELF_H */
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c
new file mode 100644
index 000000000000..46c326db4f46
--- /dev/null
+++ b/tools/objtool/objtool.c
@@ -0,0 +1,136 @@
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
39struct cmd_struct {
40 const char *name;
41 int (*fn)(int, const char **);
42 const char *help;
43};
44
45static const char objtool_usage_string[] =
46 "objtool [OPTIONS] COMMAND [ARGS]";
47
48static struct cmd_struct objtool_cmds[] = {
49 {"check", cmd_check, "Perform stack metadata validation on an object file" },
50};
51
52bool help;
53
54static 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
76static 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
99static 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
118int 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}
diff --git a/tools/objtool/special.c b/tools/objtool/special.c
new file mode 100644
index 000000000000..bff8abb3a4aa
--- /dev/null
+++ b/tools/objtool/special.c
@@ -0,0 +1,193 @@
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
46struct 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
54struct 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
81static 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 */
153int 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}
diff --git a/tools/objtool/special.h b/tools/objtool/special.h
new file mode 100644
index 000000000000..fad1d092f679
--- /dev/null
+++ b/tools/objtool/special.h
@@ -0,0 +1,42 @@
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
24struct 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
40int special_get_alts(struct elf *elf, struct list_head *alts);
41
42#endif /* _SPECIAL_H */
diff --git a/tools/objtool/warn.h b/tools/objtool/warn.h
new file mode 100644
index 000000000000..ac7e07523e84
--- /dev/null
+++ b/tools/objtool/warn.h
@@ -0,0 +1,60 @@
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
21extern const char *objname;
22
23static 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 */