aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/Kconfig.debug9
-rw-r--r--arch/x86/Makefile3
-rw-r--r--arch/x86/include/asm/inat.h188
-rw-r--r--arch/x86/include/asm/inat_types.h29
-rw-r--r--arch/x86/include/asm/insn.h143
-rw-r--r--arch/x86/include/asm/ptrace.h62
-rw-r--r--arch/x86/kernel/entry_32.S24
-rw-r--r--arch/x86/kernel/entry_64.S8
-rw-r--r--arch/x86/kernel/kprobes.c234
-rw-r--r--arch/x86/kernel/ptrace.c112
-rw-r--r--arch/x86/lib/Makefile13
-rw-r--r--arch/x86/lib/inat.c78
-rw-r--r--arch/x86/lib/insn.c464
-rw-r--r--arch/x86/lib/x86-opcode-map.txt835
-rw-r--r--arch/x86/mm/fault.c11
-rw-r--r--arch/x86/tools/Makefile15
-rw-r--r--arch/x86/tools/distill.awk42
-rw-r--r--arch/x86/tools/gen-insn-attr-x86.awk334
-rw-r--r--arch/x86/tools/test_get_len.c108
19 files changed, 2579 insertions, 133 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index d105f29bb6bb..7d0b681a132b 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -186,6 +186,15 @@ config X86_DS_SELFTEST
186config HAVE_MMIOTRACE_SUPPORT 186config HAVE_MMIOTRACE_SUPPORT
187 def_bool y 187 def_bool y
188 188
189config X86_DECODER_SELFTEST
190 bool "x86 instruction decoder selftest"
191 depends on DEBUG_KERNEL
192 ---help---
193 Perform x86 instruction decoder selftests at build time.
194 This option is useful for checking the sanity of x86 instruction
195 decoder code.
196 If unsure, say "N".
197
189# 198#
190# IO delay types: 199# IO delay types:
191# 200#
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index a012ee8ef803..ba7a6df4db92 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -156,6 +156,9 @@ all: bzImage
156KBUILD_IMAGE := $(boot)/bzImage 156KBUILD_IMAGE := $(boot)/bzImage
157 157
158bzImage: vmlinux 158bzImage: vmlinux
159ifeq ($(CONFIG_X86_DECODER_SELFTEST),y)
160 $(Q)$(MAKE) $(build)=arch/x86/tools posttest
161endif
159 $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE) 162 $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
160 $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot 163 $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot
161 $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@ 164 $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@
diff --git a/arch/x86/include/asm/inat.h b/arch/x86/include/asm/inat.h
new file mode 100644
index 000000000000..2866fddd1848
--- /dev/null
+++ b/arch/x86/include/asm/inat.h
@@ -0,0 +1,188 @@
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 <asm/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 instruction prefixes */
34#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */
35#define INAT_PFX_REPNE 2 /* 0xF2 */ /* LPFX2 */
36#define INAT_PFX_REPE 3 /* 0xF3 */ /* LPFX3 */
37#define INAT_PFX_LOCK 4 /* 0xF0 */
38#define INAT_PFX_CS 5 /* 0x2E */
39#define INAT_PFX_DS 6 /* 0x3E */
40#define INAT_PFX_ES 7 /* 0x26 */
41#define INAT_PFX_FS 8 /* 0x64 */
42#define INAT_PFX_GS 9 /* 0x65 */
43#define INAT_PFX_SS 10 /* 0x36 */
44#define INAT_PFX_ADDRSZ 11 /* 0x67 */
45
46#define INAT_LPREFIX_MAX 3
47
48/* Immediate size */
49#define INAT_IMM_BYTE 1
50#define INAT_IMM_WORD 2
51#define INAT_IMM_DWORD 3
52#define INAT_IMM_QWORD 4
53#define INAT_IMM_PTR 5
54#define INAT_IMM_VWORD32 6
55#define INAT_IMM_VWORD 7
56
57/* Legacy prefix */
58#define INAT_PFX_OFFS 0
59#define INAT_PFX_BITS 4
60#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1)
61#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS)
62/* Escape opcodes */
63#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS)
64#define INAT_ESC_BITS 2
65#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1)
66#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS)
67/* Group opcodes (1-16) */
68#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS)
69#define INAT_GRP_BITS 5
70#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1)
71#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS)
72/* Immediates */
73#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS)
74#define INAT_IMM_BITS 3
75#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS)
76/* Flags */
77#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS)
78#define INAT_REXPFX (1 << INAT_FLAG_OFFS)
79#define INAT_MODRM (1 << (INAT_FLAG_OFFS + 1))
80#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 2))
81#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 3))
82#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 4))
83#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 5))
84/* Attribute making macros for attribute tables */
85#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
86#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
87#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM)
88#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS)
89
90/* Attribute search APIs */
91extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode);
92extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode,
93 insn_byte_t last_pfx,
94 insn_attr_t esc_attr);
95extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm,
96 insn_byte_t last_pfx,
97 insn_attr_t esc_attr);
98
99/* Attribute checking functions */
100static inline int inat_is_prefix(insn_attr_t attr)
101{
102 return attr & INAT_PFX_MASK;
103}
104
105static inline int inat_is_address_size_prefix(insn_attr_t attr)
106{
107 return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ;
108}
109
110static inline int inat_is_operand_size_prefix(insn_attr_t attr)
111{
112 return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ;
113}
114
115static inline int inat_last_prefix_id(insn_attr_t attr)
116{
117 if ((attr & INAT_PFX_MASK) > INAT_LPREFIX_MAX)
118 return 0;
119 else
120 return attr & INAT_PFX_MASK;
121}
122
123static inline int inat_is_escape(insn_attr_t attr)
124{
125 return attr & INAT_ESC_MASK;
126}
127
128static inline int inat_escape_id(insn_attr_t attr)
129{
130 return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS;
131}
132
133static inline int inat_is_group(insn_attr_t attr)
134{
135 return attr & INAT_GRP_MASK;
136}
137
138static inline int inat_group_id(insn_attr_t attr)
139{
140 return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS;
141}
142
143static inline int inat_group_common_attribute(insn_attr_t attr)
144{
145 return attr & ~INAT_GRP_MASK;
146}
147
148static inline int inat_has_immediate(insn_attr_t attr)
149{
150 return attr & INAT_IMM_MASK;
151}
152
153static inline int inat_immediate_size(insn_attr_t attr)
154{
155 return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS;
156}
157
158static inline int inat_is_rex_prefix(insn_attr_t attr)
159{
160 return attr & INAT_REXPFX;
161}
162
163static inline int inat_has_modrm(insn_attr_t attr)
164{
165 return attr & INAT_MODRM;
166}
167
168static inline int inat_is_force64(insn_attr_t attr)
169{
170 return attr & INAT_FORCE64;
171}
172
173static inline int inat_has_second_immediate(insn_attr_t attr)
174{
175 return attr & INAT_SCNDIMM;
176}
177
178static inline int inat_has_moffset(insn_attr_t attr)
179{
180 return attr & INAT_MOFFSET;
181}
182
183static inline int inat_has_variant(insn_attr_t attr)
184{
185 return attr & INAT_VARIANT;
186}
187
188#endif
diff --git a/arch/x86/include/asm/inat_types.h b/arch/x86/include/asm/inat_types.h
new file mode 100644
index 000000000000..cb3c20ce39cf
--- /dev/null
+++ b/arch/x86/include/asm/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/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h
new file mode 100644
index 000000000000..12b4e3751d3f
--- /dev/null
+++ b/arch/x86/include/asm/insn.h
@@ -0,0 +1,143 @@
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 <asm/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 opcode; /*
43 * opcode.bytes[0]: opcode1
44 * opcode.bytes[1]: opcode2
45 * opcode.bytes[2]: opcode3
46 */
47 struct insn_field modrm;
48 struct insn_field sib;
49 struct insn_field displacement;
50 union {
51 struct insn_field immediate;
52 struct insn_field moffset1; /* for 64bit MOV */
53 struct insn_field immediate1; /* for 64bit imm or off16/32 */
54 };
55 union {
56 struct insn_field moffset2; /* for 64bit MOV */
57 struct insn_field immediate2; /* for 64bit imm or seg16 */
58 };
59
60 insn_attr_t attr;
61 unsigned char opnd_bytes;
62 unsigned char addr_bytes;
63 unsigned char length;
64 unsigned char x86_64;
65
66 const insn_byte_t *kaddr; /* kernel address of insn to analyze */
67 const insn_byte_t *next_byte;
68};
69
70#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6)
71#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3)
72#define X86_MODRM_RM(modrm) ((modrm) & 0x07)
73
74#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6)
75#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3)
76#define X86_SIB_BASE(sib) ((sib) & 0x07)
77
78#define X86_REX_W(rex) ((rex) & 8)
79#define X86_REX_R(rex) ((rex) & 4)
80#define X86_REX_X(rex) ((rex) & 2)
81#define X86_REX_B(rex) ((rex) & 1)
82
83/* The last prefix is needed for two-byte and three-byte opcodes */
84static inline insn_byte_t insn_last_prefix(struct insn *insn)
85{
86 return insn->prefixes.bytes[3];
87}
88
89extern void insn_init(struct insn *insn, const void *kaddr, int x86_64);
90extern void insn_get_prefixes(struct insn *insn);
91extern void insn_get_opcode(struct insn *insn);
92extern void insn_get_modrm(struct insn *insn);
93extern void insn_get_sib(struct insn *insn);
94extern void insn_get_displacement(struct insn *insn);
95extern void insn_get_immediate(struct insn *insn);
96extern void insn_get_length(struct insn *insn);
97
98/* Attribute will be determined after getting ModRM (for opcode groups) */
99static inline void insn_get_attribute(struct insn *insn)
100{
101 insn_get_modrm(insn);
102}
103
104/* Instruction uses RIP-relative addressing */
105extern int insn_rip_relative(struct insn *insn);
106
107/* Init insn for kernel text */
108static inline void kernel_insn_init(struct insn *insn, const void *kaddr)
109{
110#ifdef CONFIG_X86_64
111 insn_init(insn, kaddr, 1);
112#else /* CONFIG_X86_32 */
113 insn_init(insn, kaddr, 0);
114#endif
115}
116
117/* Offset of each field from kaddr */
118static inline int insn_offset_rex_prefix(struct insn *insn)
119{
120 return insn->prefixes.nbytes;
121}
122static inline int insn_offset_opcode(struct insn *insn)
123{
124 return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes;
125}
126static inline int insn_offset_modrm(struct insn *insn)
127{
128 return insn_offset_opcode(insn) + insn->opcode.nbytes;
129}
130static inline int insn_offset_sib(struct insn *insn)
131{
132 return insn_offset_modrm(insn) + insn->modrm.nbytes;
133}
134static inline int insn_offset_displacement(struct insn *insn)
135{
136 return insn_offset_sib(insn) + insn->sib.nbytes;
137}
138static inline int insn_offset_immediate(struct insn *insn)
139{
140 return insn_offset_displacement(insn) + insn->displacement.nbytes;
141}
142
143#endif /* _ASM_X86_INSN_H */
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 0f0d908349aa..a3d49dd7d26e 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -7,6 +7,7 @@
7 7
8#ifdef __KERNEL__ 8#ifdef __KERNEL__
9#include <asm/segment.h> 9#include <asm/segment.h>
10#include <asm/page_types.h>
10#endif 11#endif
11 12
12#ifndef __ASSEMBLY__ 13#ifndef __ASSEMBLY__
@@ -216,6 +217,67 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
216 return regs->sp; 217 return regs->sp;
217} 218}
218 219
220/* Query offset/name of register from its name/offset */
221extern int regs_query_register_offset(const char *name);
222extern const char *regs_query_register_name(unsigned int offset);
223#define MAX_REG_OFFSET (offsetof(struct pt_regs, ss))
224
225/**
226 * regs_get_register() - get register value from its offset
227 * @regs: pt_regs from which register value is gotten.
228 * @offset: offset number of the register.
229 *
230 * regs_get_register returns the value of a register whose offset from @regs
231 * is @offset. The @offset is the offset of the register in struct pt_regs.
232 * If @offset is bigger than MAX_REG_OFFSET, this returns 0.
233 */
234static inline unsigned long regs_get_register(struct pt_regs *regs,
235 unsigned int offset)
236{
237 if (unlikely(offset > MAX_REG_OFFSET))
238 return 0;
239 return *(unsigned long *)((unsigned long)regs + offset);
240}
241
242/**
243 * regs_within_kernel_stack() - check the address in the stack
244 * @regs: pt_regs which contains kernel stack pointer.
245 * @addr: address which is checked.
246 *
247 * regs_within_kenel_stack() checks @addr is within the kernel stack page(s).
248 * If @addr is within the kernel stack, it returns true. If not, returns false.
249 */
250static inline int regs_within_kernel_stack(struct pt_regs *regs,
251 unsigned long addr)
252{
253 return ((addr & ~(THREAD_SIZE - 1)) ==
254 (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
255}
256
257/**
258 * regs_get_kernel_stack_nth() - get Nth entry of the stack
259 * @regs: pt_regs which contains kernel stack pointer.
260 * @n: stack entry number.
261 *
262 * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
263 * is specifined by @regs. If the @n th entry is NOT in the kernel stack,
264 * this returns 0.
265 */
266static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
267 unsigned int n)
268{
269 unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
270 addr += n;
271 if (regs_within_kernel_stack(regs, (unsigned long)addr))
272 return *addr;
273 else
274 return 0;
275}
276
277/* Get Nth argument at function call */
278extern unsigned long regs_get_argument_nth(struct pt_regs *regs,
279 unsigned int n);
280
219/* 281/*
220 * These are defined as per linux/ptrace.h, which see. 282 * These are defined as per linux/ptrace.h, which see.
221 */ 283 */
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index c097e7d607c6..beb30da203d6 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -334,6 +334,10 @@ ENTRY(ret_from_fork)
334END(ret_from_fork) 334END(ret_from_fork)
335 335
336/* 336/*
337 * Interrupt exit functions should be protected against kprobes
338 */
339 .pushsection .kprobes.text, "ax"
340/*
337 * Return to user mode is not as complex as all this looks, 341 * Return to user mode is not as complex as all this looks,
338 * but we want the default path for a system call return to 342 * but we want the default path for a system call return to
339 * go as quickly as possible which is why some of this is 343 * go as quickly as possible which is why some of this is
@@ -383,6 +387,10 @@ need_resched:
383END(resume_kernel) 387END(resume_kernel)
384#endif 388#endif
385 CFI_ENDPROC 389 CFI_ENDPROC
390/*
391 * End of kprobes section
392 */
393 .popsection
386 394
387/* SYSENTER_RETURN points to after the "sysenter" instruction in 395/* SYSENTER_RETURN points to after the "sysenter" instruction in
388 the vsyscall page. See vsyscall-sysentry.S, which defines the symbol. */ 396 the vsyscall page. See vsyscall-sysentry.S, which defines the symbol. */
@@ -513,6 +521,10 @@ sysexit_audit:
513 PTGS_TO_GS_EX 521 PTGS_TO_GS_EX
514ENDPROC(ia32_sysenter_target) 522ENDPROC(ia32_sysenter_target)
515 523
524/*
525 * syscall stub including irq exit should be protected against kprobes
526 */
527 .pushsection .kprobes.text, "ax"
516 # system call handler stub 528 # system call handler stub
517ENTRY(system_call) 529ENTRY(system_call)
518 RING0_INT_FRAME # can't unwind into user space anyway 530 RING0_INT_FRAME # can't unwind into user space anyway
@@ -705,6 +717,10 @@ syscall_badsys:
705 jmp resume_userspace 717 jmp resume_userspace
706END(syscall_badsys) 718END(syscall_badsys)
707 CFI_ENDPROC 719 CFI_ENDPROC
720/*
721 * End of kprobes section
722 */
723 .popsection
708 724
709/* 725/*
710 * System calls that need a pt_regs pointer. 726 * System calls that need a pt_regs pointer.
@@ -814,6 +830,10 @@ common_interrupt:
814ENDPROC(common_interrupt) 830ENDPROC(common_interrupt)
815 CFI_ENDPROC 831 CFI_ENDPROC
816 832
833/*
834 * Irq entries should be protected against kprobes
835 */
836 .pushsection .kprobes.text, "ax"
817#define BUILD_INTERRUPT3(name, nr, fn) \ 837#define BUILD_INTERRUPT3(name, nr, fn) \
818ENTRY(name) \ 838ENTRY(name) \
819 RING0_INT_FRAME; \ 839 RING0_INT_FRAME; \
@@ -980,6 +1000,10 @@ ENTRY(spurious_interrupt_bug)
980 jmp error_code 1000 jmp error_code
981 CFI_ENDPROC 1001 CFI_ENDPROC
982END(spurious_interrupt_bug) 1002END(spurious_interrupt_bug)
1003/*
1004 * End of kprobes section
1005 */
1006 .popsection
983 1007
984ENTRY(kernel_thread_helper) 1008ENTRY(kernel_thread_helper)
985 pushl $0 # fake return address for unwinder 1009 pushl $0 # fake return address for unwinder
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index b5c061f8f358..42a0b2cbf2e1 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -803,6 +803,10 @@ END(interrupt)
803 call \func 803 call \func
804 .endm 804 .endm
805 805
806/*
807 * Interrupt entry/exit should be protected against kprobes
808 */
809 .pushsection .kprobes.text, "ax"
806 /* 810 /*
807 * The interrupt stubs push (~vector+0x80) onto the stack and 811 * The interrupt stubs push (~vector+0x80) onto the stack and
808 * then jump to common_interrupt. 812 * then jump to common_interrupt.
@@ -941,6 +945,10 @@ ENTRY(retint_kernel)
941 945
942 CFI_ENDPROC 946 CFI_ENDPROC
943END(common_interrupt) 947END(common_interrupt)
948/*
949 * End of kprobes section
950 */
951 .popsection
944 952
945/* 953/*
946 * APIC interrupts. 954 * APIC interrupts.
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index 7b5169d2b000..c5f1f117e0c0 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -48,12 +48,14 @@
48#include <linux/preempt.h> 48#include <linux/preempt.h>
49#include <linux/module.h> 49#include <linux/module.h>
50#include <linux/kdebug.h> 50#include <linux/kdebug.h>
51#include <linux/kallsyms.h>
51 52
52#include <asm/cacheflush.h> 53#include <asm/cacheflush.h>
53#include <asm/desc.h> 54#include <asm/desc.h>
54#include <asm/pgtable.h> 55#include <asm/pgtable.h>
55#include <asm/uaccess.h> 56#include <asm/uaccess.h>
56#include <asm/alternative.h> 57#include <asm/alternative.h>
58#include <asm/insn.h>
57 59
58void jprobe_return_end(void); 60void jprobe_return_end(void);
59 61
@@ -106,50 +108,6 @@ static const u32 twobyte_is_boostable[256 / 32] = {
106 /* ----------------------------------------------- */ 108 /* ----------------------------------------------- */
107 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ 109 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
108}; 110};
109static const u32 onebyte_has_modrm[256 / 32] = {
110 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
111 /* ----------------------------------------------- */
112 W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 00 */
113 W(0x10, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 10 */
114 W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 20 */
115 W(0x30, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) , /* 30 */
116 W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */
117 W(0x50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 50 */
118 W(0x60, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0) | /* 60 */
119 W(0x70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 70 */
120 W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
121 W(0x90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 90 */
122 W(0xa0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* a0 */
123 W(0xb0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* b0 */
124 W(0xc0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* c0 */
125 W(0xd0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
126 W(0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* e0 */
127 W(0xf0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) /* f0 */
128 /* ----------------------------------------------- */
129 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
130};
131static const u32 twobyte_has_modrm[256 / 32] = {
132 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
133 /* ----------------------------------------------- */
134 W(0x00, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1) | /* 0f */
135 W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0) , /* 1f */
136 W(0x20, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 2f */
137 W(0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 3f */
138 W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 4f */
139 W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 5f */
140 W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 6f */
141 W(0x70, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1) , /* 7f */
142 W(0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 8f */
143 W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 9f */
144 W(0xa0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1) | /* af */
145 W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1) , /* bf */
146 W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0) | /* cf */
147 W(0xd0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* df */
148 W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* ef */
149 W(0xf0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) /* ff */
150 /* ----------------------------------------------- */
151 /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
152};
153#undef W 111#undef W
154 112
155struct kretprobe_blackpoint kretprobe_blacklist[] = { 113struct kretprobe_blackpoint kretprobe_blacklist[] = {
@@ -244,6 +202,75 @@ retry:
244 } 202 }
245} 203}
246 204
205/* Recover the probed instruction at addr for further analysis. */
206static int recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
207{
208 struct kprobe *kp;
209 kp = get_kprobe((void *)addr);
210 if (!kp)
211 return -EINVAL;
212
213 /*
214 * Basically, kp->ainsn.insn has an original instruction.
215 * However, RIP-relative instruction can not do single-stepping
216 * at different place, fix_riprel() tweaks the displacement of
217 * that instruction. In that case, we can't recover the instruction
218 * from the kp->ainsn.insn.
219 *
220 * On the other hand, kp->opcode has a copy of the first byte of
221 * the probed instruction, which is overwritten by int3. And
222 * the instruction at kp->addr is not modified by kprobes except
223 * for the first byte, we can recover the original instruction
224 * from it and kp->opcode.
225 */
226 memcpy(buf, kp->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
227 buf[0] = kp->opcode;
228 return 0;
229}
230
231/* Dummy buffers for kallsyms_lookup */
232static char __dummy_buf[KSYM_NAME_LEN];
233
234/* Check if paddr is at an instruction boundary */
235static int __kprobes can_probe(unsigned long paddr)
236{
237 int ret;
238 unsigned long addr, offset = 0;
239 struct insn insn;
240 kprobe_opcode_t buf[MAX_INSN_SIZE];
241
242 if (!kallsyms_lookup(paddr, NULL, &offset, NULL, __dummy_buf))
243 return 0;
244
245 /* Decode instructions */
246 addr = paddr - offset;
247 while (addr < paddr) {
248 kernel_insn_init(&insn, (void *)addr);
249 insn_get_opcode(&insn);
250
251 /*
252 * Check if the instruction has been modified by another
253 * kprobe, in which case we replace the breakpoint by the
254 * original instruction in our buffer.
255 */
256 if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION) {
257 ret = recover_probed_instruction(buf, addr);
258 if (ret)
259 /*
260 * Another debugging subsystem might insert
261 * this breakpoint. In that case, we can't
262 * recover it.
263 */
264 return 0;
265 kernel_insn_init(&insn, buf);
266 }
267 insn_get_length(&insn);
268 addr += insn.length;
269 }
270
271 return (addr == paddr);
272}
273
247/* 274/*
248 * Returns non-zero if opcode modifies the interrupt flag. 275 * Returns non-zero if opcode modifies the interrupt flag.
249 */ 276 */
@@ -277,68 +304,30 @@ static int __kprobes is_IF_modifier(kprobe_opcode_t *insn)
277static void __kprobes fix_riprel(struct kprobe *p) 304static void __kprobes fix_riprel(struct kprobe *p)
278{ 305{
279#ifdef CONFIG_X86_64 306#ifdef CONFIG_X86_64
280 u8 *insn = p->ainsn.insn; 307 struct insn insn;
281 s64 disp; 308 kernel_insn_init(&insn, p->ainsn.insn);
282 int need_modrm;
283
284 /* Skip legacy instruction prefixes. */
285 while (1) {
286 switch (*insn) {
287 case 0x66:
288 case 0x67:
289 case 0x2e:
290 case 0x3e:
291 case 0x26:
292 case 0x64:
293 case 0x65:
294 case 0x36:
295 case 0xf0:
296 case 0xf3:
297 case 0xf2:
298 ++insn;
299 continue;
300 }
301 break;
302 }
303 309
304 /* Skip REX instruction prefix. */ 310 if (insn_rip_relative(&insn)) {
305 if (is_REX_prefix(insn)) 311 s64 newdisp;
306 ++insn; 312 u8 *disp;
307 313 insn_get_displacement(&insn);
308 if (*insn == 0x0f) { 314 /*
309 /* Two-byte opcode. */ 315 * The copied instruction uses the %rip-relative addressing
310 ++insn; 316 * mode. Adjust the displacement for the difference between
311 need_modrm = test_bit(*insn, 317 * the original location of this instruction and the location
312 (unsigned long *)twobyte_has_modrm); 318 * of the copy that will actually be run. The tricky bit here
313 } else 319 * is making sure that the sign extension happens correctly in
314 /* One-byte opcode. */ 320 * this calculation, since we need a signed 32-bit result to
315 need_modrm = test_bit(*insn, 321 * be sign-extended to 64 bits when it's added to the %rip
316 (unsigned long *)onebyte_has_modrm); 322 * value and yield the same 64-bit result that the sign-
317 323 * extension of the original signed 32-bit displacement would
318 if (need_modrm) { 324 * have given.
319 u8 modrm = *++insn; 325 */
320 if ((modrm & 0xc7) == 0x05) { 326 newdisp = (u8 *) p->addr + (s64) insn.displacement.value -
321 /* %rip+disp32 addressing mode */ 327 (u8 *) p->ainsn.insn;
322 /* Displacement follows ModRM byte. */ 328 BUG_ON((s64) (s32) newdisp != newdisp); /* Sanity check. */
323 ++insn; 329 disp = (u8 *) p->ainsn.insn + insn_offset_displacement(&insn);
324 /* 330 *(s32 *) disp = (s32) newdisp;
325 * The copied instruction uses the %rip-relative
326 * addressing mode. Adjust the displacement for the
327 * difference between the original location of this
328 * instruction and the location of the copy that will
329 * actually be run. The tricky bit here is making sure
330 * that the sign extension happens correctly in this
331 * calculation, since we need a signed 32-bit result to
332 * be sign-extended to 64 bits when it's added to the
333 * %rip value and yield the same 64-bit result that the
334 * sign-extension of the original signed 32-bit
335 * displacement would have given.
336 */
337 disp = (u8 *) p->addr + *((s32 *) insn) -
338 (u8 *) p->ainsn.insn;
339 BUG_ON((s64) (s32) disp != disp); /* Sanity check. */
340 *(s32 *)insn = (s32) disp;
341 }
342 } 331 }
343#endif 332#endif
344} 333}
@@ -359,6 +348,8 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p)
359 348
360int __kprobes arch_prepare_kprobe(struct kprobe *p) 349int __kprobes arch_prepare_kprobe(struct kprobe *p)
361{ 350{
351 if (!can_probe((unsigned long)p->addr))
352 return -EILSEQ;
362 /* insn: must be on special executable page on x86. */ 353 /* insn: must be on special executable page on x86. */
363 p->ainsn.insn = get_insn_slot(); 354 p->ainsn.insn = get_insn_slot();
364 if (!p->ainsn.insn) 355 if (!p->ainsn.insn)
@@ -472,17 +463,6 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
472{ 463{
473 switch (kcb->kprobe_status) { 464 switch (kcb->kprobe_status) {
474 case KPROBE_HIT_SSDONE: 465 case KPROBE_HIT_SSDONE:
475#ifdef CONFIG_X86_64
476 /* TODO: Provide re-entrancy from post_kprobes_handler() and
477 * avoid exception stack corruption while single-stepping on
478 * the instruction of the new probe.
479 */
480 arch_disarm_kprobe(p);
481 regs->ip = (unsigned long)p->addr;
482 reset_current_kprobe();
483 preempt_enable_no_resched();
484 break;
485#endif
486 case KPROBE_HIT_ACTIVE: 466 case KPROBE_HIT_ACTIVE:
487 save_previous_kprobe(kcb); 467 save_previous_kprobe(kcb);
488 set_current_kprobe(p, regs, kcb); 468 set_current_kprobe(p, regs, kcb);
@@ -491,18 +471,16 @@ static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
491 kcb->kprobe_status = KPROBE_REENTER; 471 kcb->kprobe_status = KPROBE_REENTER;
492 break; 472 break;
493 case KPROBE_HIT_SS: 473 case KPROBE_HIT_SS:
494 if (p == kprobe_running()) { 474 /* A probe has been hit in the codepath leading up to, or just
495 regs->flags &= ~X86_EFLAGS_TF; 475 * after, single-stepping of a probed instruction. This entire
496 regs->flags |= kcb->kprobe_saved_flags; 476 * codepath should strictly reside in .kprobes.text section.
497 return 0; 477 * Raise a BUG or we'll continue in an endless reentering loop
498 } else { 478 * and eventually a stack overflow.
499 /* A probe has been hit in the codepath leading up 479 */
500 * to, or just after, single-stepping of a probed 480 printk(KERN_WARNING "Unrecoverable kprobe detected at %p.\n",
501 * instruction. This entire codepath should strictly 481 p->addr);
502 * reside in .kprobes.text section. Raise a warning 482 dump_kprobe(p);
503 * to highlight this peculiar case. 483 BUG();
504 */
505 }
506 default: 484 default:
507 /* impossible cases */ 485 /* impossible cases */
508 WARN_ON(1); 486 WARN_ON(1);
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 7b058a2dc66a..c4f76d275ee4 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -49,6 +49,118 @@ enum x86_regset {
49 REGSET_IOPERM32, 49 REGSET_IOPERM32,
50}; 50};
51 51
52struct pt_regs_offset {
53 const char *name;
54 int offset;
55};
56
57#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
58#define REG_OFFSET_END {.name = NULL, .offset = 0}
59
60static const struct pt_regs_offset regoffset_table[] = {
61#ifdef CONFIG_X86_64
62 REG_OFFSET_NAME(r15),
63 REG_OFFSET_NAME(r14),
64 REG_OFFSET_NAME(r13),
65 REG_OFFSET_NAME(r12),
66 REG_OFFSET_NAME(r11),
67 REG_OFFSET_NAME(r10),
68 REG_OFFSET_NAME(r9),
69 REG_OFFSET_NAME(r8),
70#endif
71 REG_OFFSET_NAME(bx),
72 REG_OFFSET_NAME(cx),
73 REG_OFFSET_NAME(dx),
74 REG_OFFSET_NAME(si),
75 REG_OFFSET_NAME(di),
76 REG_OFFSET_NAME(bp),
77 REG_OFFSET_NAME(ax),
78#ifdef CONFIG_X86_32
79 REG_OFFSET_NAME(ds),
80 REG_OFFSET_NAME(es),
81 REG_OFFSET_NAME(fs),
82 REG_OFFSET_NAME(gs),
83#endif
84 REG_OFFSET_NAME(orig_ax),
85 REG_OFFSET_NAME(ip),
86 REG_OFFSET_NAME(cs),
87 REG_OFFSET_NAME(flags),
88 REG_OFFSET_NAME(sp),
89 REG_OFFSET_NAME(ss),
90 REG_OFFSET_END,
91};
92
93/**
94 * regs_query_register_offset() - query register offset from its name
95 * @name: the name of a register
96 *
97 * regs_query_register_offset() returns the offset of a register in struct
98 * pt_regs from its name. If the name is invalid, this returns -EINVAL;
99 */
100int regs_query_register_offset(const char *name)
101{
102 const struct pt_regs_offset *roff;
103 for (roff = regoffset_table; roff->name != NULL; roff++)
104 if (!strcmp(roff->name, name))
105 return roff->offset;
106 return -EINVAL;
107}
108
109/**
110 * regs_query_register_name() - query register name from its offset
111 * @offset: the offset of a register in struct pt_regs.
112 *
113 * regs_query_register_name() returns the name of a register from its
114 * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
115 */
116const char *regs_query_register_name(unsigned int offset)
117{
118 const struct pt_regs_offset *roff;
119 for (roff = regoffset_table; roff->name != NULL; roff++)
120 if (roff->offset == offset)
121 return roff->name;
122 return NULL;
123}
124
125static const int arg_offs_table[] = {
126#ifdef CONFIG_X86_32
127 [0] = offsetof(struct pt_regs, ax),
128 [1] = offsetof(struct pt_regs, dx),
129 [2] = offsetof(struct pt_regs, cx)
130#else /* CONFIG_X86_64 */
131 [0] = offsetof(struct pt_regs, di),
132 [1] = offsetof(struct pt_regs, si),
133 [2] = offsetof(struct pt_regs, dx),
134 [3] = offsetof(struct pt_regs, cx),
135 [4] = offsetof(struct pt_regs, r8),
136 [5] = offsetof(struct pt_regs, r9)
137#endif
138};
139
140/**
141 * regs_get_argument_nth() - get Nth argument at function call
142 * @regs: pt_regs which contains registers at function entry.
143 * @n: argument number.
144 *
145 * regs_get_argument_nth() returns @n th argument of a function call.
146 * Since usually the kernel stack will be changed right after function entry,
147 * you must use this at function entry. If the @n th entry is NOT in the
148 * kernel stack or pt_regs, this returns 0.
149 */
150unsigned long regs_get_argument_nth(struct pt_regs *regs, unsigned int n)
151{
152 if (n < ARRAY_SIZE(arg_offs_table))
153 return *(unsigned long *)((char *)regs + arg_offs_table[n]);
154 else {
155 /*
156 * The typical case: arg n is on the stack.
157 * (Note: stack[0] = return address, so skip it)
158 */
159 n -= ARRAY_SIZE(arg_offs_table);
160 return regs_get_kernel_stack_nth(regs, 1 + n);
161 }
162}
163
52/* 164/*
53 * does not yet catch signals sent when the child dies. 165 * does not yet catch signals sent when the child dies.
54 * in exit.c or in signal.c. 166 * in exit.c or in signal.c.
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 85f5db95c60f..a2d6472895fb 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -2,12 +2,25 @@
2# Makefile for x86 specific library files. 2# Makefile for x86 specific library files.
3# 3#
4 4
5inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
6inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt
7quiet_cmd_inat_tables = GEN $@
8 cmd_inat_tables = $(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@
9
10$(obj)/inat-tables.c: $(inat_tables_script) $(inat_tables_maps)
11 $(call cmd,inat_tables)
12
13$(obj)/inat.o: $(obj)/inat-tables.c
14
15clean-files := inat-tables.c
16
5obj-$(CONFIG_SMP) := msr.o 17obj-$(CONFIG_SMP) := msr.o
6 18
7lib-y := delay.o 19lib-y := delay.o
8lib-y += thunk_$(BITS).o 20lib-y += thunk_$(BITS).o
9lib-y += usercopy_$(BITS).o getuser.o putuser.o 21lib-y += usercopy_$(BITS).o getuser.o putuser.o
10lib-y += memcpy_$(BITS).o 22lib-y += memcpy_$(BITS).o
23lib-y += insn.o inat.o
11 24
12obj-y += msr-reg.o msr-reg-export.o 25obj-y += msr-reg.o msr-reg-export.o
13 26
diff --git a/arch/x86/lib/inat.c b/arch/x86/lib/inat.c
new file mode 100644
index 000000000000..054656a01dfd
--- /dev/null
+++ b/arch/x86/lib/inat.c
@@ -0,0 +1,78 @@
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 <asm/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
32insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, insn_byte_t last_pfx,
33 insn_attr_t esc_attr)
34{
35 const insn_attr_t *table;
36 insn_attr_t lpfx_attr;
37 int n, m = 0;
38
39 n = inat_escape_id(esc_attr);
40 if (last_pfx) {
41 lpfx_attr = inat_get_opcode_attribute(last_pfx);
42 m = inat_last_prefix_id(lpfx_attr);
43 }
44 table = inat_escape_tables[n][0];
45 if (!table)
46 return 0;
47 if (inat_has_variant(table[opcode]) && m) {
48 table = inat_escape_tables[n][m];
49 if (!table)
50 return 0;
51 }
52 return table[opcode];
53}
54
55insn_attr_t inat_get_group_attribute(insn_byte_t modrm, insn_byte_t last_pfx,
56 insn_attr_t grp_attr)
57{
58 const insn_attr_t *table;
59 insn_attr_t lpfx_attr;
60 int n, m = 0;
61
62 n = inat_group_id(grp_attr);
63 if (last_pfx) {
64 lpfx_attr = inat_get_opcode_attribute(last_pfx);
65 m = inat_last_prefix_id(lpfx_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)]) && m) {
71 table = inat_escape_tables[n][m];
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
diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c
new file mode 100644
index 000000000000..dfd56a30053f
--- /dev/null
+++ b/arch/x86/lib/insn.c
@@ -0,0 +1,464 @@
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#include <linux/string.h>
22#include <asm/inat.h>
23#include <asm/insn.h>
24
25#define get_next(t, insn) \
26 ({t r; r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; })
27
28#define peek_next(t, insn) \
29 ({t r; r = *(t*)insn->next_byte; r; })
30
31/**
32 * insn_init() - initialize struct insn
33 * @insn: &struct insn to be initialized
34 * @kaddr: address (in kernel memory) of instruction (or copy thereof)
35 * @x86_64: !0 for 64-bit kernel or 64-bit app
36 */
37void insn_init(struct insn *insn, const void *kaddr, int x86_64)
38{
39 memset(insn, 0, sizeof(*insn));
40 insn->kaddr = kaddr;
41 insn->next_byte = kaddr;
42 insn->x86_64 = x86_64 ? 1 : 0;
43 insn->opnd_bytes = 4;
44 if (x86_64)
45 insn->addr_bytes = 8;
46 else
47 insn->addr_bytes = 4;
48}
49
50/**
51 * insn_get_prefixes - scan x86 instruction prefix bytes
52 * @insn: &struct insn containing instruction
53 *
54 * Populates the @insn->prefixes bitmap, and updates @insn->next_byte
55 * to point to the (first) opcode. No effect if @insn->prefixes.got
56 * is already set.
57 */
58void insn_get_prefixes(struct insn *insn)
59{
60 struct insn_field *prefixes = &insn->prefixes;
61 insn_attr_t attr;
62 insn_byte_t b, lb;
63 int i, nb;
64
65 if (prefixes->got)
66 return;
67
68 nb = 0;
69 lb = 0;
70 b = peek_next(insn_byte_t, insn);
71 attr = inat_get_opcode_attribute(b);
72 while (inat_is_prefix(attr)) {
73 /* Skip if same prefix */
74 for (i = 0; i < nb; i++)
75 if (prefixes->bytes[i] == b)
76 goto found;
77 if (nb == 4)
78 /* Invalid instruction */
79 break;
80 prefixes->bytes[nb++] = b;
81 if (inat_is_address_size_prefix(attr)) {
82 /* address size switches 2/4 or 4/8 */
83 if (insn->x86_64)
84 insn->addr_bytes ^= 12;
85 else
86 insn->addr_bytes ^= 6;
87 } else if (inat_is_operand_size_prefix(attr)) {
88 /* oprand size switches 2/4 */
89 insn->opnd_bytes ^= 6;
90 }
91found:
92 prefixes->nbytes++;
93 insn->next_byte++;
94 lb = b;
95 b = peek_next(insn_byte_t, insn);
96 attr = inat_get_opcode_attribute(b);
97 }
98 /* Set the last prefix */
99 if (lb && lb != insn->prefixes.bytes[3]) {
100 if (unlikely(insn->prefixes.bytes[3])) {
101 /* Swap the last prefix */
102 b = insn->prefixes.bytes[3];
103 for (i = 0; i < nb; i++)
104 if (prefixes->bytes[i] == lb)
105 prefixes->bytes[i] = b;
106 }
107 insn->prefixes.bytes[3] = lb;
108 }
109
110 if (insn->x86_64) {
111 b = peek_next(insn_byte_t, insn);
112 attr = inat_get_opcode_attribute(b);
113 if (inat_is_rex_prefix(attr)) {
114 insn->rex_prefix.value = b;
115 insn->rex_prefix.nbytes = 1;
116 insn->next_byte++;
117 if (X86_REX_W(b))
118 /* REX.W overrides opnd_size */
119 insn->opnd_bytes = 8;
120 }
121 }
122 insn->rex_prefix.got = 1;
123 prefixes->got = 1;
124 return;
125}
126
127/**
128 * insn_get_opcode - collect opcode(s)
129 * @insn: &struct insn containing instruction
130 *
131 * Populates @insn->opcode, updates @insn->next_byte to point past the
132 * opcode byte(s), and set @insn->attr (except for groups).
133 * If necessary, first collects any preceding (prefix) bytes.
134 * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got
135 * is already 1.
136 */
137void insn_get_opcode(struct insn *insn)
138{
139 struct insn_field *opcode = &insn->opcode;
140 insn_byte_t op, pfx;
141 if (opcode->got)
142 return;
143 if (!insn->prefixes.got)
144 insn_get_prefixes(insn);
145
146 /* Get first opcode */
147 op = get_next(insn_byte_t, insn);
148 opcode->bytes[0] = op;
149 opcode->nbytes = 1;
150 insn->attr = inat_get_opcode_attribute(op);
151 while (inat_is_escape(insn->attr)) {
152 /* Get escaped opcode */
153 op = get_next(insn_byte_t, insn);
154 opcode->bytes[opcode->nbytes++] = op;
155 pfx = insn_last_prefix(insn);
156 insn->attr = inat_get_escape_attribute(op, pfx, insn->attr);
157 }
158 opcode->got = 1;
159}
160
161/**
162 * insn_get_modrm - collect ModRM byte, if any
163 * @insn: &struct insn containing instruction
164 *
165 * Populates @insn->modrm and updates @insn->next_byte to point past the
166 * ModRM byte, if any. If necessary, first collects the preceding bytes
167 * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1.
168 */
169void insn_get_modrm(struct insn *insn)
170{
171 struct insn_field *modrm = &insn->modrm;
172 insn_byte_t pfx, mod;
173 if (modrm->got)
174 return;
175 if (!insn->opcode.got)
176 insn_get_opcode(insn);
177
178 if (inat_has_modrm(insn->attr)) {
179 mod = get_next(insn_byte_t, insn);
180 modrm->value = mod;
181 modrm->nbytes = 1;
182 if (inat_is_group(insn->attr)) {
183 pfx = insn_last_prefix(insn);
184 insn->attr = inat_get_group_attribute(mod, pfx,
185 insn->attr);
186 }
187 }
188
189 if (insn->x86_64 && inat_is_force64(insn->attr))
190 insn->opnd_bytes = 8;
191 modrm->got = 1;
192}
193
194
195/**
196 * insn_rip_relative() - Does instruction use RIP-relative addressing mode?
197 * @insn: &struct insn containing instruction
198 *
199 * If necessary, first collects the instruction up to and including the
200 * ModRM byte. No effect if @insn->x86_64 is 0.
201 */
202int insn_rip_relative(struct insn *insn)
203{
204 struct insn_field *modrm = &insn->modrm;
205
206 if (!insn->x86_64)
207 return 0;
208 if (!modrm->got)
209 insn_get_modrm(insn);
210 /*
211 * For rip-relative instructions, the mod field (top 2 bits)
212 * is zero and the r/m field (bottom 3 bits) is 0x5.
213 */
214 return (modrm->nbytes && (modrm->value & 0xc7) == 0x5);
215}
216
217/**
218 * insn_get_sib() - Get the SIB byte of instruction
219 * @insn: &struct insn containing instruction
220 *
221 * If necessary, first collects the instruction up to and including the
222 * ModRM byte.
223 */
224void insn_get_sib(struct insn *insn)
225{
226 insn_byte_t modrm;
227
228 if (insn->sib.got)
229 return;
230 if (!insn->modrm.got)
231 insn_get_modrm(insn);
232 if (insn->modrm.nbytes) {
233 modrm = (insn_byte_t)insn->modrm.value;
234 if (insn->addr_bytes != 2 &&
235 X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) {
236 insn->sib.value = get_next(insn_byte_t, insn);
237 insn->sib.nbytes = 1;
238 }
239 }
240 insn->sib.got = 1;
241}
242
243
244/**
245 * insn_get_displacement() - Get the displacement of instruction
246 * @insn: &struct insn containing instruction
247 *
248 * If necessary, first collects the instruction up to and including the
249 * SIB byte.
250 * Displacement value is sign-expanded.
251 */
252void insn_get_displacement(struct insn *insn)
253{
254 insn_byte_t mod, rm, base;
255
256 if (insn->displacement.got)
257 return;
258 if (!insn->sib.got)
259 insn_get_sib(insn);
260 if (insn->modrm.nbytes) {
261 /*
262 * Interpreting the modrm byte:
263 * mod = 00 - no displacement fields (exceptions below)
264 * mod = 01 - 1-byte displacement field
265 * mod = 10 - displacement field is 4 bytes, or 2 bytes if
266 * address size = 2 (0x67 prefix in 32-bit mode)
267 * mod = 11 - no memory operand
268 *
269 * If address size = 2...
270 * mod = 00, r/m = 110 - displacement field is 2 bytes
271 *
272 * If address size != 2...
273 * mod != 11, r/m = 100 - SIB byte exists
274 * mod = 00, SIB base = 101 - displacement field is 4 bytes
275 * mod = 00, r/m = 101 - rip-relative addressing, displacement
276 * field is 4 bytes
277 */
278 mod = X86_MODRM_MOD(insn->modrm.value);
279 rm = X86_MODRM_RM(insn->modrm.value);
280 base = X86_SIB_BASE(insn->sib.value);
281 if (mod == 3)
282 goto out;
283 if (mod == 1) {
284 insn->displacement.value = get_next(char, insn);
285 insn->displacement.nbytes = 1;
286 } else if (insn->addr_bytes == 2) {
287 if ((mod == 0 && rm == 6) || mod == 2) {
288 insn->displacement.value =
289 get_next(short, insn);
290 insn->displacement.nbytes = 2;
291 }
292 } else {
293 if ((mod == 0 && rm == 5) || mod == 2 ||
294 (mod == 0 && base == 5)) {
295 insn->displacement.value = get_next(int, insn);
296 insn->displacement.nbytes = 4;
297 }
298 }
299 }
300out:
301 insn->displacement.got = 1;
302}
303
304/* Decode moffset16/32/64 */
305static void __get_moffset(struct insn *insn)
306{
307 switch (insn->addr_bytes) {
308 case 2:
309 insn->moffset1.value = get_next(short, insn);
310 insn->moffset1.nbytes = 2;
311 break;
312 case 4:
313 insn->moffset1.value = get_next(int, insn);
314 insn->moffset1.nbytes = 4;
315 break;
316 case 8:
317 insn->moffset1.value = get_next(int, insn);
318 insn->moffset1.nbytes = 4;
319 insn->moffset2.value = get_next(int, insn);
320 insn->moffset2.nbytes = 4;
321 break;
322 }
323 insn->moffset1.got = insn->moffset2.got = 1;
324}
325
326/* Decode imm v32(Iz) */
327static void __get_immv32(struct insn *insn)
328{
329 switch (insn->opnd_bytes) {
330 case 2:
331 insn->immediate.value = get_next(short, insn);
332 insn->immediate.nbytes = 2;
333 break;
334 case 4:
335 case 8:
336 insn->immediate.value = get_next(int, insn);
337 insn->immediate.nbytes = 4;
338 break;
339 }
340}
341
342/* Decode imm v64(Iv/Ov) */
343static void __get_immv(struct insn *insn)
344{
345 switch (insn->opnd_bytes) {
346 case 2:
347 insn->immediate1.value = get_next(short, insn);
348 insn->immediate1.nbytes = 2;
349 break;
350 case 4:
351 insn->immediate1.value = get_next(int, insn);
352 insn->immediate1.nbytes = 4;
353 break;
354 case 8:
355 insn->immediate1.value = get_next(int, insn);
356 insn->immediate1.nbytes = 4;
357 insn->immediate2.value = get_next(int, insn);
358 insn->immediate2.nbytes = 4;
359 break;
360 }
361 insn->immediate1.got = insn->immediate2.got = 1;
362}
363
364/* Decode ptr16:16/32(Ap) */
365static void __get_immptr(struct insn *insn)
366{
367 switch (insn->opnd_bytes) {
368 case 2:
369 insn->immediate1.value = get_next(short, insn);
370 insn->immediate1.nbytes = 2;
371 break;
372 case 4:
373 insn->immediate1.value = get_next(int, insn);
374 insn->immediate1.nbytes = 4;
375 break;
376 case 8:
377 /* ptr16:64 is not exist (no segment) */
378 return;
379 }
380 insn->immediate2.value = get_next(unsigned short, insn);
381 insn->immediate2.nbytes = 2;
382 insn->immediate1.got = insn->immediate2.got = 1;
383}
384
385/**
386 * insn_get_immediate() - Get the immediates of instruction
387 * @insn: &struct insn containing instruction
388 *
389 * If necessary, first collects the instruction up to and including the
390 * displacement bytes.
391 * Basically, most of immediates are sign-expanded. Unsigned-value can be
392 * get by bit masking with ((1 << (nbytes * 8)) - 1)
393 */
394void insn_get_immediate(struct insn *insn)
395{
396 if (insn->immediate.got)
397 return;
398 if (!insn->displacement.got)
399 insn_get_displacement(insn);
400
401 if (inat_has_moffset(insn->attr)) {
402 __get_moffset(insn);
403 goto done;
404 }
405
406 if (!inat_has_immediate(insn->attr))
407 /* no immediates */
408 goto done;
409
410 switch (inat_immediate_size(insn->attr)) {
411 case INAT_IMM_BYTE:
412 insn->immediate.value = get_next(char, insn);
413 insn->immediate.nbytes = 1;
414 break;
415 case INAT_IMM_WORD:
416 insn->immediate.value = get_next(short, insn);
417 insn->immediate.nbytes = 2;
418 break;
419 case INAT_IMM_DWORD:
420 insn->immediate.value = get_next(int, insn);
421 insn->immediate.nbytes = 4;
422 break;
423 case INAT_IMM_QWORD:
424 insn->immediate1.value = get_next(int, insn);
425 insn->immediate1.nbytes = 4;
426 insn->immediate2.value = get_next(int, insn);
427 insn->immediate2.nbytes = 4;
428 break;
429 case INAT_IMM_PTR:
430 __get_immptr(insn);
431 break;
432 case INAT_IMM_VWORD32:
433 __get_immv32(insn);
434 break;
435 case INAT_IMM_VWORD:
436 __get_immv(insn);
437 break;
438 default:
439 break;
440 }
441 if (inat_has_second_immediate(insn->attr)) {
442 insn->immediate2.value = get_next(char, insn);
443 insn->immediate2.nbytes = 1;
444 }
445done:
446 insn->immediate.got = 1;
447}
448
449/**
450 * insn_get_length() - Get the length of instruction
451 * @insn: &struct insn containing instruction
452 *
453 * If necessary, first collects the instruction up to and including the
454 * immediates bytes.
455 */
456void insn_get_length(struct insn *insn)
457{
458 if (insn->length)
459 return;
460 if (!insn->immediate.got)
461 insn_get_immediate(insn);
462 insn->length = (unsigned char)((unsigned long)insn->next_byte
463 - (unsigned long)insn->kaddr);
464}
diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt
new file mode 100644
index 000000000000..894497f77808
--- /dev/null
+++ b/arch/x86/lib/x86-opcode-map.txt
@@ -0,0 +1,835 @@
1# x86 Opcode Maps
2#
3#<Opcode maps>
4# Table: table-name
5# Referrer: escaped-name
6# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...]
7# (or)
8# opcode: escape # escaped-name
9# EndTable
10#
11#<group maps>
12# GrpTable: GrpXXX
13# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...]
14# EndTable
15#
16
17Table: one byte opcode
18Referrer:
19# 0x00 - 0x0f
2000: ADD Eb,Gb
2101: ADD Ev,Gv
2202: ADD Gb,Eb
2303: ADD Gv,Ev
2404: ADD AL,Ib
2505: ADD rAX,Iz
2606: PUSH ES (i64)
2707: POP ES (i64)
2808: OR Eb,Gb
2909: OR Ev,Gv
300a: OR Gb,Eb
310b: OR Gv,Ev
320c: OR AL,Ib
330d: OR rAX,Iz
340e: PUSH CS (i64)
350f: escape # 2-byte escape
36# 0x10 - 0x1f
3710: ADC Eb,Gb
3811: ADC Ev,Gv
3912: ADC Gb,Eb
4013: ADC Gv,Ev
4114: ADC AL,Ib
4215: ADC rAX,Iz
4316: PUSH SS (i64)
4417: POP SS (i64)
4518: SBB Eb,Gb
4619: SBB Ev,Gv
471a: SBB Gb,Eb
481b: SBB Gv,Ev
491c: SBB AL,Ib
501d: SBB rAX,Iz
511e: PUSH DS (i64)
521f: POP DS (i64)
53# 0x20 - 0x2f
5420: AND Eb,Gb
5521: AND Ev,Gv
5622: AND Gb,Eb
5723: AND Gv,Ev
5824: AND AL,Ib
5925: AND rAx,Iz
6026: SEG=ES (Prefix)
6127: DAA (i64)
6228: SUB Eb,Gb
6329: SUB Ev,Gv
642a: SUB Gb,Eb
652b: SUB Gv,Ev
662c: SUB AL,Ib
672d: SUB rAX,Iz
682e: SEG=CS (Prefix)
692f: DAS (i64)
70# 0x30 - 0x3f
7130: XOR Eb,Gb
7231: XOR Ev,Gv
7332: XOR Gb,Eb
7433: XOR Gv,Ev
7534: XOR AL,Ib
7635: XOR rAX,Iz
7736: SEG=SS (Prefix)
7837: AAA (i64)
7938: CMP Eb,Gb
8039: CMP Ev,Gv
813a: CMP Gb,Eb
823b: CMP Gv,Ev
833c: CMP AL,Ib
843d: CMP rAX,Iz
853e: SEG=DS (Prefix)
863f: AAS (i64)
87# 0x40 - 0x4f
8840: INC eAX (i64) | REX (o64)
8941: INC eCX (i64) | REX.B (o64)
9042: INC eDX (i64) | REX.X (o64)
9143: INC eBX (i64) | REX.XB (o64)
9244: INC eSP (i64) | REX.R (o64)
9345: INC eBP (i64) | REX.RB (o64)
9446: INC eSI (i64) | REX.RX (o64)
9547: INC eDI (i64) | REX.RXB (o64)
9648: DEC eAX (i64) | REX.W (o64)
9749: DEC eCX (i64) | REX.WB (o64)
984a: DEC eDX (i64) | REX.WX (o64)
994b: DEC eBX (i64) | REX.WXB (o64)
1004c: DEC eSP (i64) | REX.WR (o64)
1014d: DEC eBP (i64) | REX.WRB (o64)
1024e: DEC eSI (i64) | REX.WRX (o64)
1034f: DEC eDI (i64) | REX.WRXB (o64)
104# 0x50 - 0x5f
10550: PUSH rAX/r8 (d64)
10651: PUSH rCX/r9 (d64)
10752: PUSH rDX/r10 (d64)
10853: PUSH rBX/r11 (d64)
10954: PUSH rSP/r12 (d64)
11055: PUSH rBP/r13 (d64)
11156: PUSH rSI/r14 (d64)
11257: PUSH rDI/r15 (d64)
11358: POP rAX/r8 (d64)
11459: POP rCX/r9 (d64)
1155a: POP rDX/r10 (d64)
1165b: POP rBX/r11 (d64)
1175c: POP rSP/r12 (d64)
1185d: POP rBP/r13 (d64)
1195e: POP rSI/r14 (d64)
1205f: POP rDI/r15 (d64)
121# 0x60 - 0x6f
12260: PUSHA/PUSHAD (i64)
12361: POPA/POPAD (i64)
12462: BOUND Gv,Ma (i64)
12563: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64)
12664: SEG=FS (Prefix)
12765: SEG=GS (Prefix)
12866: Operand-Size (Prefix)
12967: Address-Size (Prefix)
13068: PUSH Iz (d64)
13169: IMUL Gv,Ev,Iz
1326a: PUSH Ib (d64)
1336b: IMUL Gv,Ev,Ib
1346c: INS/INSB Yb,DX
1356d: INS/INSW/INSD Yz,DX
1366e: OUTS/OUTSB DX,Xb
1376f: OUTS/OUTSW/OUTSD DX,Xz
138# 0x70 - 0x7f
13970: JO Jb
14071: JNO Jb
14172: JB/JNAE/JC Jb
14273: JNB/JAE/JNC Jb
14374: JZ/JE Jb
14475: JNZ/JNE Jb
14576: JBE/JNA Jb
14677: JNBE/JA Jb
14778: JS Jb
14879: JNS Jb
1497a: JP/JPE Jb
1507b: JNP/JPO Jb
1517c: JL/JNGE Jb
1527d: JNL/JGE Jb
1537e: JLE/JNG Jb
1547f: JNLE/JG Jb
155# 0x80 - 0x8f
15680: Grp1 Eb,Ib (1A)
15781: Grp1 Ev,Iz (1A)
15882: Grp1 Eb,Ib (1A),(i64)
15983: Grp1 Ev,Ib (1A)
16084: TEST Eb,Gb
16185: TEST Ev,Gv
16286: XCHG Eb,Gb
16387: XCHG Ev,Gv
16488: MOV Eb,Gb
16589: MOV Ev,Gv
1668a: MOV Gb,Eb
1678b: MOV Gv,Ev
1688c: MOV Ev,Sw
1698d: LEA Gv,M
1708e: MOV Sw,Ew
1718f: Grp1A (1A) | POP Ev (d64)
172# 0x90 - 0x9f
17390: NOP | PAUSE (F3) | XCHG r8,rAX
17491: XCHG rCX/r9,rAX
17592: XCHG rDX/r10,rAX
17693: XCHG rBX/r11,rAX
17794: XCHG rSP/r12,rAX
17895: XCHG rBP/r13,rAX
17996: XCHG rSI/r14,rAX
18097: XCHG rDI/r15,rAX
18198: CBW/CWDE/CDQE
18299: CWD/CDQ/CQO
1839a: CALLF Ap (i64)
1849b: FWAIT/WAIT
1859c: PUSHF/D/Q Fv (d64)
1869d: POPF/D/Q Fv (d64)
1879e: SAHF
1889f: LAHF
189# 0xa0 - 0xaf
190a0: MOV AL,Ob
191a1: MOV rAX,Ov
192a2: MOV Ob,AL
193a3: MOV Ov,rAX
194a4: MOVS/B Xb,Yb
195a5: MOVS/W/D/Q Xv,Yv
196a6: CMPS/B Xb,Yb
197a7: CMPS/W/D Xv,Yv
198a8: TEST AL,Ib
199a9: TEST rAX,Iz
200aa: STOS/B Yb,AL
201ab: STOS/W/D/Q Yv,rAX
202ac: LODS/B AL,Xb
203ad: LODS/W/D/Q rAX,Xv
204ae: SCAS/B AL,Yb
205af: SCAS/W/D/Q rAX,Xv
206# 0xb0 - 0xbf
207b0: MOV AL/R8L,Ib
208b1: MOV CL/R9L,Ib
209b2: MOV DL/R10L,Ib
210b3: MOV BL/R11L,Ib
211b4: MOV AH/R12L,Ib
212b5: MOV CH/R13L,Ib
213b6: MOV DH/R14L,Ib
214b7: MOV BH/R15L,Ib
215b8: MOV rAX/r8,Iv
216b9: MOV rCX/r9,Iv
217ba: MOV rDX/r10,Iv
218bb: MOV rBX/r11,Iv
219bc: MOV rSP/r12,Iv
220bd: MOV rBP/r13,Iv
221be: MOV rSI/r14,Iv
222bf: MOV rDI/r15,Iv
223# 0xc0 - 0xcf
224c0: Grp2 Eb,Ib (1A)
225c1: Grp2 Ev,Ib (1A)
226c2: RETN Iw (f64)
227c3: RETN
228c4: LES Gz,Mp (i64)
229c5: LDS Gz,Mp (i64)
230c6: Grp11 Eb,Ib (1A)
231c7: Grp11 Ev,Iz (1A)
232c8: ENTER Iw,Ib
233c9: LEAVE (d64)
234ca: RETF Iw
235cb: RETF
236cc: INT3
237cd: INT Ib
238ce: INTO (i64)
239cf: IRET/D/Q
240# 0xd0 - 0xdf
241d0: Grp2 Eb,1 (1A)
242d1: Grp2 Ev,1 (1A)
243d2: Grp2 Eb,CL (1A)
244d3: Grp2 Ev,CL (1A)
245d4: AAM Ib (i64)
246d5: AAD Ib (i64)
247d6:
248d7: XLAT/XLATB
249d8: ESC
250d9: ESC
251da: ESC
252db: ESC
253dc: ESC
254dd: ESC
255de: ESC
256df: ESC
257# 0xe0 - 0xef
258e0: LOOPNE/LOOPNZ Jb (f64)
259e1: LOOPE/LOOPZ Jb (f64)
260e2: LOOP Jb (f64)
261e3: JrCXZ Jb (f64)
262e4: IN AL,Ib
263e5: IN eAX,Ib
264e6: OUT Ib,AL
265e7: OUT Ib,eAX
266e8: CALL Jz (f64)
267e9: JMP-near Jz (f64)
268ea: JMP-far Ap (i64)
269eb: JMP-short Jb (f64)
270ec: IN AL,DX
271ed: IN eAX,DX
272ee: OUT DX,AL
273ef: OUT DX,eAX
274# 0xf0 - 0xff
275f0: LOCK (Prefix)
276f1:
277f2: REPNE (Prefix)
278f3: REP/REPE (Prefix)
279f4: HLT
280f5: CMC
281f6: Grp3_1 Eb (1A)
282f7: Grp3_2 Ev (1A)
283f8: CLC
284f9: STC
285fa: CLI
286fb: STI
287fc: CLD
288fd: STD
289fe: Grp4 (1A)
290ff: Grp5 (1A)
291EndTable
292
293Table: 2-byte opcode # First Byte is 0x0f
294Referrer: 2-byte escape
295# 0x0f 0x00-0x0f
29600: Grp6 (1A)
29701: Grp7 (1A)
29802: LAR Gv,Ew
29903: LSL Gv,Ew
30004:
30105: SYSCALL (o64)
30206: CLTS
30307: SYSRET (o64)
30408: INVD
30509: WBINVD
3060a:
3070b: UD2 (1B)
3080c:
3090d: NOP Ev | GrpP
3100e: FEMMS
311# 3DNow! uses the last imm byte as opcode extension.
3120f: 3DNow! Pq,Qq,Ib
313# 0x0f 0x10-0x1f
31410: movups Vps,Wps | movss Vss,Wss (F3) | movupd Vpd,Wpd (66) | movsd Vsd,Wsd (F2)
31511: movups Wps,Vps | movss Wss,Vss (F3) | movupd Wpd,Vpd (66) | movsd Wsd,Vsd (F2)
31612: movlps Vq,Mq | movlpd Vq,Mq (66) | movhlps Vq,Uq | movddup Vq,Wq (F2) | movsldup Vq,Wq (F3)
31713: mpvlps Mq,Vq | movlpd Mq,Vq (66)
31814: unpcklps Vps,Wq | unpcklpd Vpd,Wq (66)
31915: unpckhps Vps,Wq | unpckhpd Vpd,Wq (66)
32016: movhps Vq,Mq | movhpd Vq,Mq (66) | movlsps Vq,Uq | movshdup Vq,Wq (F3)
32117: movhps Mq,Vq | movhpd Mq,Vq (66)
32218: Grp16 (1A)
32319:
3241a:
3251b:
3261c:
3271d:
3281e:
3291f: NOP Ev
330# 0x0f 0x20-0x2f
33120: MOV Rd,Cd
33221: MOV Rd,Dd
33322: MOV Cd,Rd
33423: MOV Dd,Rd
33524:
33625:
33726:
33827:
33928: movaps Vps,Wps | movapd Vpd,Wpd (66)
34029: movaps Wps,Vps | movapd Wpd,Vpd (66)
3412a: cvtpi2ps Vps,Qpi | cvtsi2ss Vss,Ed/q (F3) | cvtpi2pd Vpd,Qpi (66) | cvtsi2sd Vsd,Ed/q (F2)
3422b: movntps Mps,Vps | movntpd Mpd,Vpd (66)
3432c: cvttps2pi Ppi,Wps | cvttss2si Gd/q,Wss (F3) | cvttpd2pi Ppi,Wpd (66) | cvttsd2si Gd/q,Wsd (F2)
3442d: cvtps2pi Ppi,Wps | cvtss2si Gd/q,Wss (F3) | cvtpd2pi Qpi,Wpd (66) | cvtsd2si Gd/q,Wsd (F2)
3452e: ucomiss Vss,Wss | ucomisd Vsd,Wsd (66)
3462f: comiss Vss,Wss | comisd Vsd,Wsd (66)
347# 0x0f 0x30-0x3f
34830: WRMSR
34931: RDTSC
35032: RDMSR
35133: RDPMC
35234: SYSENTER
35335: SYSEXIT
35436:
35537: GETSEC
35638: escape # 3-byte escape 1
35739:
3583a: escape # 3-byte escape 2
3593b:
3603c:
3613d:
3623e:
3633f:
364# 0x0f 0x40-0x4f
36540: CMOVO Gv,Ev
36641: CMOVNO Gv,Ev
36742: CMOVB/C/NAE Gv,Ev
36843: CMOVAE/NB/NC Gv,Ev
36944: CMOVE/Z Gv,Ev
37045: CMOVNE/NZ Gv,Ev
37146: CMOVBE/NA Gv,Ev
37247: CMOVA/NBE Gv,Ev
37348: CMOVS Gv,Ev
37449: CMOVNS Gv,Ev
3754a: CMOVP/PE Gv,Ev
3764b: CMOVNP/PO Gv,Ev
3774c: CMOVL/NGE Gv,Ev
3784d: CMOVNL/GE Gv,Ev
3794e: CMOVLE/NG Gv,Ev
3804f: CMOVNLE/G Gv,Ev
381# 0x0f 0x50-0x5f
38250: movmskps Gd/q,Ups | movmskpd Gd/q,Upd (66)
38351: sqrtps Vps,Wps | sqrtss Vss,Wss (F3) | sqrtpd Vpd,Wpd (66) | sqrtsd Vsd,Wsd (F2)
38452: rsqrtps Vps,Wps | rsqrtss Vss,Wss (F3)
38553: rcpps Vps,Wps | rcpss Vss,Wss (F3)
38654: andps Vps,Wps | andpd Vpd,Wpd (66)
38755: andnps Vps,Wps | andnpd Vpd,Wpd (66)
38856: orps Vps,Wps | orpd Vpd,Wpd (66)
38957: xorps Vps,Wps | xorpd Vpd,Wpd (66)
39058: addps Vps,Wps | addss Vss,Wss (F3) | addpd Vpd,Wpd (66) | addsd Vsd,Wsd (F2)
39159: mulps Vps,Wps | mulss Vss,Wss (F3) | mulpd Vpd,Wpd (66) | mulsd Vsd,Wsd (F2)
3925a: cvtps2pd Vpd,Wps | cvtss2sd Vsd,Wss (F3) | cvtpd2ps Vps,Wpd (66) | cvtsd2ss Vsd,Wsd (F2)
3935b: cvtdq2ps Vps,Wdq | cvtps2dq Vdq,Wps (66) | cvttps2dq Vdq,Wps (F3)
3945c: subps Vps,Wps | subss Vss,Wss (F3) | subpd Vpd,Wpd (66) | subsd Vsd,Wsd (F2)
3955d: minps Vps,Wps | minss Vss,Wss (F3) | minpd Vpd,Wpd (66) | minsd Vsd,Wsd (F2)
3965e: divps Vps,Wps | divss Vss,Wss (F3) | divpd Vpd,Wpd (66) | divsd Vsd,Wsd (F2)
3975f: maxps Vps,Wps | maxss Vss,Wss (F3) | maxpd Vpd,Wpd (66) | maxsd Vsd,Wsd (F2)
398# 0x0f 0x60-0x6f
39960: punpcklbw Pq,Qd | punpcklbw Vdq,Wdq (66)
40061: punpcklwd Pq,Qd | punpcklwd Vdq,Wdq (66)
40162: punpckldq Pq,Qd | punpckldq Vdq,Wdq (66)
40263: packsswb Pq,Qq | packsswb Vdq,Wdq (66)
40364: pcmpgtb Pq,Qq | pcmpgtb Vdq,Wdq (66)
40465: pcmpgtw Pq,Qq | pcmpgtw(66) Vdq,Wdq
40566: pcmpgtd Pq,Qq | pcmpgtd Vdq,Wdq (66)
40667: packuswb Pq,Qq | packuswb(66) Vdq,Wdq
40768: punpckhbw Pq,Qd | punpckhbw Vdq,Wdq (66)
40869: punpckhwd Pq,Qd | punpckhwd Vdq,Wdq (66)
4096a: punpckhdq Pq,Qd | punpckhdq Vdq,Wdq (66)
4106b: packssdw Pq,Qd | packssdw Vdq,Wdq (66)
4116c: punpcklqdq Vdq,Wdq (66)
4126d: punpckhqdq Vdq,Wdq (66)
4136e: movd/q/ Pd,Ed/q | movd/q Vdq,Ed/q (66)
4146f: movq Pq,Qq | movdqa Vdq,Wdq (66) | movdqu Vdq,Wdq (F3)
415# 0x0f 0x70-0x7f
41670: pshufw Pq,Qq,Ib | pshufd Vdq,Wdq,Ib (66) | pshufhw Vdq,Wdq,Ib (F3) | pshuflw VdqWdq,Ib (F2)
41771: Grp12 (1A)
41872: Grp13 (1A)
41973: Grp14 (1A)
42074: pcmpeqb Pq,Qq | pcmpeqb Vdq,Wdq (66)
42175: pcmpeqw Pq,Qq | pcmpeqw Vdq,Wdq (66)
42276: pcmpeqd Pq,Qq | pcmpeqd Vdq,Wdq (66)
42377: emms
42478: VMREAD Ed/q,Gd/q
42579: VMWRITE Gd/q,Ed/q
4267a:
4277b:
4287c: haddps(F2) Vps,Wps | haddpd(66) Vpd,Wpd
4297d: hsubps(F2) Vps,Wps | hsubpd(66) Vpd,Wpd
4307e: movd/q Ed/q,Pd | movd/q Ed/q,Vdq (66) | movq Vq,Wq (F3)
4317f: movq Qq,Pq | movdqa Wdq,Vdq (66) | movdqu Wdq,Vdq (F3)
432# 0x0f 0x80-0x8f
43380: JO Jz (f64)
43481: JNO Jz (f64)
43582: JB/JNAE/JC Jz (f64)
43683: JNB/JAE/JNC Jz (f64)
43784: JZ/JE Jz (f64)
43885: JNZ/JNE Jz (f64)
43986: JBE/JNA Jz (f64)
44087: JNBE/JA Jz (f64)
44188: JS Jz (f64)
44289: JNS Jz (f64)
4438a: JP/JPE Jz (f64)
4448b: JNP/JPO Jz (f64)
4458c: JL/JNGE Jz (f64)
4468d: JNL/JGE Jz (f64)
4478e: JLE/JNG Jz (f64)
4488f: JNLE/JG Jz (f64)
449# 0x0f 0x90-0x9f
45090: SETO Eb
45191: SETNO Eb
45292: SETB/C/NAE Eb
45393: SETAE/NB/NC Eb
45494: SETE/Z Eb
45595: SETNE/NZ Eb
45696: SETBE/NA Eb
45797: SETA/NBE Eb
45898: SETS Eb
45999: SETNS Eb
4609a: SETP/PE Eb
4619b: SETNP/PO Eb
4629c: SETL/NGE Eb
4639d: SETNL/GE Eb
4649e: SETLE/NG Eb
4659f: SETNLE/G Eb
466# 0x0f 0xa0-0xaf
467a0: PUSH FS (d64)
468a1: POP FS (d64)
469a2: CPUID
470a3: BT Ev,Gv
471a4: SHLD Ev,Gv,Ib
472a5: SHLD Ev,Gv,CL
473a6: GrpPDLK
474a7: GrpRNG
475a8: PUSH GS (d64)
476a9: POP GS (d64)
477aa: RSM
478ab: BTS Ev,Gv
479ac: SHRD Ev,Gv,Ib
480ad: SHRD Ev,Gv,CL
481ae: Grp15 (1A),(1C)
482af: IMUL Gv,Ev
483# 0x0f 0xb0-0xbf
484b0: CMPXCHG Eb,Gb
485b1: CMPXCHG Ev,Gv
486b2: LSS Gv,Mp
487b3: BTR Ev,Gv
488b4: LFS Gv,Mp
489b5: LGS Gv,Mp
490b6: MOVZX Gv,Eb
491b7: MOVZX Gv,Ew
492b8: JMPE | POPCNT Gv,Ev (F3)
493b9: Grp10 (1A)
494ba: Grp8 Ev,Ib (1A)
495bb: BTC Ev,Gv
496bc: BSF Gv,Ev
497bd: BSR Gv,Ev
498be: MOVSX Gv,Eb
499bf: MOVSX Gv,Ew
500# 0x0f 0xc0-0xcf
501c0: XADD Eb,Gb
502c1: XADD Ev,Gv
503c2: cmpps Vps,Wps,Ib | cmpss Vss,Wss,Ib (F3) | cmppd Vpd,Wpd,Ib (66) | cmpsd Vsd,Wsd,Ib (F2)
504c3: movnti Md/q,Gd/q
505c4: pinsrw Pq,Rd/q/Mw,Ib | pinsrw Vdq,Rd/q/Mw,Ib (66)
506c5: pextrw Gd,Nq,Ib | pextrw Gd,Udq,Ib (66)
507c6: shufps Vps,Wps,Ib | shufpd Vpd,Wpd,Ib (66)
508c7: Grp9 (1A)
509c8: BSWAP RAX/EAX/R8/R8D
510c9: BSWAP RCX/ECX/R9/R9D
511ca: BSWAP RDX/EDX/R10/R10D
512cb: BSWAP RBX/EBX/R11/R11D
513cc: BSWAP RSP/ESP/R12/R12D
514cd: BSWAP RBP/EBP/R13/R13D
515ce: BSWAP RSI/ESI/R14/R14D
516cf: BSWAP RDI/EDI/R15/R15D
517# 0x0f 0xd0-0xdf
518d0: addsubps Vps,Wps (F2) | addsubpd Vpd,Wpd (66)
519d1: psrlw Pq,Qq | psrlw Vdq,Wdq (66)
520d2: psrld Pq,Qq | psrld Vdq,Wdq (66)
521d3: psrlq Pq,Qq | psrlq Vdq,Wdq (66)
522d4: paddq Pq,Qq | paddq Vdq,Wdq (66)
523d5: pmullw Pq,Qq | pmullw Vdq,Wdq (66)
524d6: movq Wq,Vq (66) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2)
525d7: pmovmskb Gd,Nq | pmovmskb Gd,Udq (66)
526d8: psubusb Pq,Qq | psubusb Vdq,Wdq (66)
527d9: psubusw Pq,Qq | psubusw Vdq,Wdq (66)
528da: pminub Pq,Qq | pminub Vdq,Wdq (66)
529db: pand Pq,Qq | pand Vdq,Wdq (66)
530dc: paddusb Pq,Qq | paddusb Vdq,Wdq (66)
531dd: paddusw Pq,Qq | paddusw Vdq,Wdq (66)
532de: pmaxub Pq,Qq | pmaxub Vdq,Wdq (66)
533df: pandn Pq,Qq | pandn Vdq,Wdq (66)
534# 0x0f 0xe0-0xef
535e0: pavgb Pq,Qq | pavgb Vdq,Wdq (66)
536e1: psraw Pq,Qq | psraw Vdq,Wdq (66)
537e2: psrad Pq,Qq | psrad Vdq,Wdq (66)
538e3: pavgw Pq,Qq | pavgw Vdq,Wdq (66)
539e4: pmulhuw Pq,Qq | pmulhuw Vdq,Wdq (66)
540e5: pmulhw Pq,Qq | pmulhw Vdq,Wdq (66)
541e6: cvtpd2dq Vdq,Wpd (F2) | cvttpd2dq Vdq,Wpd (66) | cvtdq2pd Vpd,Wdq (F3)
542e7: movntq Mq,Pq | movntdq Mdq,Vdq (66)
543e8: psubsb Pq,Qq | psubsb Vdq,Wdq (66)
544e9: psubsw Pq,Qq | psubsw Vdq,Wdq (66)
545ea: pminsw Pq,Qq | pminsw Vdq,Wdq (66)
546eb: por Pq,Qq | por Vdq,Wdq (66)
547ec: paddsb Pq,Qq | paddsb Vdq,Wdq (66)
548ed: paddsw Pq,Qq | paddsw Vdq,Wdq (66)
549ee: pmaxsw Pq,Qq | pmaxsw Vdq,Wdq (66)
550ef: pxor Pq,Qq | pxor Vdq,Wdq (66)
551# 0x0f 0xf0-0xff
552f0: lddqu Vdq,Mdq (F2)
553f1: psllw Pq,Qq | psllw Vdq,Wdq (66)
554f2: pslld Pq,Qq | pslld Vdq,Wdq (66)
555f3: psllq Pq,Qq | psllq Vdq,Wdq (66)
556f4: pmuludq Pq,Qq | pmuludq Vdq,Wdq (66)
557f5: pmaddwd Pq,Qq | pmaddwd Vdq,Wdq (66)
558f6: psadbw Pq,Qq | psadbw Vdq,Wdq (66)
559f7: maskmovq Pq,Nq | maskmovdqu Vdq,Udq (66)
560f8: psubb Pq,Qq | psubb Vdq,Wdq (66)
561f9: psubw Pq,Qq | psubw Vdq,Wdq (66)
562fa: psubd Pq,Qq | psubd Vdq,Wdq (66)
563fb: psubq Pq,Qq | psubq Vdq,Wdq (66)
564fc: paddb Pq,Qq | paddb Vdq,Wdq (66)
565fd: paddw Pq,Qq | paddw Vdq,Wdq (66)
566fe: paddd Pq,Qq | paddd Vdq,Wdq (66)
567ff:
568EndTable
569
570Table: 3-byte opcode 1
571Referrer: 3-byte escape 1
572# 0x0f 0x38 0x00-0x0f
57300: pshufb Pq,Qq | pshufb Vdq,Wdq (66)
57401: phaddw Pq,Qq | phaddw Vdq,Wdq (66)
57502: phaddd Pq,Qq | phaddd Vdq,Wdq (66)
57603: phaddsw Pq,Qq | phaddsw Vdq,Wdq (66)
57704: pmaddubsw Pq,Qq | pmaddubsw (66)Vdq,Wdq
57805: phsubw Pq,Qq | phsubw Vdq,Wdq (66)
57906: phsubd Pq,Qq | phsubd Vdq,Wdq (66)
58007: phsubsw Pq,Qq | phsubsw Vdq,Wdq (66)
58108: psignb Pq,Qq | psignb Vdq,Wdq (66)
58209: psignw Pq,Qq | psignw Vdq,Wdq (66)
5830a: psignd Pq,Qq | psignd Vdq,Wdq (66)
5840b: pmulhrsw Pq,Qq | pmulhrsw Vdq,Wdq (66)
5850c:
5860d:
5870e:
5880f:
589# 0x0f 0x38 0x10-0x1f
59010: pblendvb Vdq,Wdq (66)
59111:
59212:
59313:
59414: blendvps Vdq,Wdq (66)
59515: blendvpd Vdq,Wdq (66)
59616:
59717: ptest Vdq,Wdq (66)
59818:
59919:
6001a:
6011b:
6021c: pabsb Pq,Qq | pabsb Vdq,Wdq (66)
6031d: pabsw Pq,Qq | pabsw Vdq,Wdq (66)
6041e: pabsd Pq,Qq | pabsd Vdq,Wdq (66)
6051f:
606# 0x0f 0x38 0x20-0x2f
60720: pmovsxbw Vdq,Udq/Mq (66)
60821: pmovsxbd Vdq,Udq/Md (66)
60922: pmovsxbq Vdq,Udq/Mw (66)
61023: pmovsxwd Vdq,Udq/Mq (66)
61124: pmovsxwq Vdq,Udq/Md (66)
61225: pmovsxdq Vdq,Udq/Mq (66)
61326:
61427:
61528: pmuldq Vdq,Wdq (66)
61629: pcmpeqq Vdq,Wdq (66)
6172a: movntdqa Vdq,Mdq (66)
6182b: packusdw Vdq,Wdq (66)
6192c:
6202d:
6212e:
6222f:
623# 0x0f 0x38 0x30-0x3f
62430: pmovzxbw Vdq,Udq/Mq (66)
62531: pmovzxbd Vdq,Udq/Md (66)
62632: pmovzxbq Vdq,Udq/Mw (66)
62733: pmovzxwd Vdq,Udq/Mq (66)
62834: pmovzxwq Vdq,Udq/Md (66)
62935: pmovzxdq Vdq,Udq/Mq (66)
63036:
63137: pcmpgtq Vdq,Wdq (66)
63238: pminsb Vdq,Wdq (66)
63339: pminsd Vdq,Wdq (66)
6343a: pminuw Vdq,Wdq (66)
6353b: pminud Vdq,Wdq (66)
6363c: pmaxsb Vdq,Wdq (66)
6373d: pmaxsd Vdq,Wdq (66)
6383e: pmaxuw Vdq,Wdq (66)
6393f: pmaxud Vdq,Wdq (66)
640# 0x0f 0x38 0x4f-0xff
64140: pmulld Vdq,Wdq (66)
64241: phminposuw Vdq,Wdq (66)
64380: INVEPT Gd/q,Mdq (66)
64481: INVPID Gd/q,Mdq (66)
645f0: MOVBE Gv,Mv | CRC32 Gd,Eb (F2)
646f1: MOVBE Mv,Gv | CRC32 Gd,Ev (F2)
647EndTable
648
649Table: 3-byte opcode 2
650Referrer: 3-byte escape 2
651# 0x0f 0x3a 0x00-0xff
65208: roundps Vdq,Wdq,Ib (66)
65309: roundpd Vdq,Wdq,Ib (66)
6540a: roundss Vss,Wss,Ib (66)
6550b: roundsd Vsd,Wsd,Ib (66)
6560c: blendps Vdq,Wdq,Ib (66)
6570d: blendpd Vdq,Wdq,Ib (66)
6580e: pblendw Vdq,Wdq,Ib (66)
6590f: palignr Pq,Qq,Ib | palignr Vdq,Wdq,Ib (66)
66014: pextrb Rd/Mb,Vdq,Ib (66)
66115: pextrw Rd/Mw,Vdq,Ib (66)
66216: pextrd/pextrq Ed/q,Vdq,Ib (66)
66317: extractps Ed,Vdq,Ib (66)
66420: pinsrb Vdq,Rd/q/Mb,Ib (66)
66521: insertps Vdq,Udq/Md,Ib (66)
66622: pinsrd/pinsrq Vdq,Ed/q,Ib (66)
66740: dpps Vdq,Wdq,Ib (66)
66841: dppd Vdq,Wdq,Ib (66)
66942: mpsadbw Vdq,Wdq,Ib (66)
67060: pcmpestrm Vdq,Wdq,Ib (66)
67161: pcmpestri Vdq,Wdq,Ib (66)
67262: pcmpistrm Vdq,Wdq,Ib (66)
67363: pcmpistri Vdq,Wdq,Ib (66)
674EndTable
675
676GrpTable: Grp1
6770: ADD
6781: OR
6792: ADC
6803: SBB
6814: AND
6825: SUB
6836: XOR
6847: CMP
685EndTable
686
687GrpTable: Grp1A
6880: POP
689EndTable
690
691GrpTable: Grp2
6920: ROL
6931: ROR
6942: RCL
6953: RCR
6964: SHL/SAL
6975: SHR
6986:
6997: SAR
700EndTable
701
702GrpTable: Grp3_1
7030: TEST Eb,Ib
7041:
7052: NOT Eb
7063: NEG Eb
7074: MUL AL,Eb
7085: IMUL AL,Eb
7096: DIV AL,Eb
7107: IDIV AL,Eb
711EndTable
712
713GrpTable: Grp3_2
7140: TEST Ev,Iz
7151:
7162: NOT Ev
7173: NEG Ev
7184: MUL rAX,Ev
7195: IMUL rAX,Ev
7206: DIV rAX,Ev
7217: IDIV rAX,Ev
722EndTable
723
724GrpTable: Grp4
7250: INC Eb
7261: DEC Eb
727EndTable
728
729GrpTable: Grp5
7300: INC Ev
7311: DEC Ev
7322: CALLN Ev (f64)
7333: CALLF Ep
7344: JMPN Ev (f64)
7355: JMPF Ep
7366: PUSH Ev (d64)
7377:
738EndTable
739
740GrpTable: Grp6
7410: SLDT Rv/Mw
7421: STR Rv/Mw
7432: LLDT Ew
7443: LTR Ew
7454: VERR Ew
7465: VERW Ew
747EndTable
748
749GrpTable: Grp7
7500: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
7511: SIDT Ms | MONITOR (000),(11B) | MWAIT (001)
7522: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B)
7533: LIDT Ms
7544: SMSW Mw/Rv
7555:
7566: LMSW Ew
7577: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B)
758EndTable
759
760GrpTable: Grp8
7614: BT
7625: BTS
7636: BTR
7647: BTC
765EndTable
766
767GrpTable: Grp9
7681: CMPXCHG8B/16B Mq/Mdq
7696: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3)
7707: VMPTRST Mq
771EndTable
772
773GrpTable: Grp10
774EndTable
775
776GrpTable: Grp11
7770: MOV
778EndTable
779
780GrpTable: Grp12
7812: psrlw Nq,Ib (11B) | psrlw Udq,Ib (66),(11B)
7824: psraw Nq,Ib (11B) | psraw Udq,Ib (66),(11B)
7836: psllw Nq,Ib (11B) | psllw Udq,Ib (66),(11B)
784EndTable
785
786GrpTable: Grp13
7872: psrld Nq,Ib (11B) | psrld Udq,Ib (66),(11B)
7884: psrad Nq,Ib (11B) | psrad Udq,Ib (66),(11B)
7896: pslld Nq,Ib (11B) | pslld Udq,Ib (66),(11B)
790EndTable
791
792GrpTable: Grp14
7932: psrlq Nq,Ib (11B) | psrlq Udq,Ib (66),(11B)
7943: psrldq Udq,Ib (66),(11B)
7956: psllq Nq,Ib (11B) | psllq Udq,Ib (66),(11B)
7967: pslldq Udq,Ib (66),(11B)
797EndTable
798
799GrpTable: Grp15
8000: fxsave
8011: fxstor
8022: ldmxcsr
8033: stmxcsr
8044: XSAVE
8055: XRSTOR | lfence (11B)
8066: mfence (11B)
8077: clflush | sfence (11B)
808EndTable
809
810GrpTable: Grp16
8110: prefetch NTA
8121: prefetch T0
8132: prefetch T1
8143: prefetch T2
815EndTable
816
817# AMD's Prefetch Group
818GrpTable: GrpP
8190: PREFETCH
8201: PREFETCHW
821EndTable
822
823GrpTable: GrpPDLK
8240: MONTMUL
8251: XSHA1
8262: XSHA2
827EndTable
828
829GrpTable: GrpRNG
8300: xstore-rng
8311: xcrypt-ecb
8322: xcrypt-cbc
8334: xcrypt-cfb
8345: xcrypt-ofb
835EndTable
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index f4cee9028cf0..8f4e2ac93928 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -38,7 +38,8 @@ enum x86_pf_error_code {
38 * Returns 0 if mmiotrace is disabled, or if the fault is not 38 * Returns 0 if mmiotrace is disabled, or if the fault is not
39 * handled by mmiotrace: 39 * handled by mmiotrace:
40 */ 40 */
41static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr) 41static inline int __kprobes
42kmmio_fault(struct pt_regs *regs, unsigned long addr)
42{ 43{
43 if (unlikely(is_kmmio_active())) 44 if (unlikely(is_kmmio_active()))
44 if (kmmio_handler(regs, addr) == 1) 45 if (kmmio_handler(regs, addr) == 1)
@@ -46,7 +47,7 @@ static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr)
46 return 0; 47 return 0;
47} 48}
48 49
49static inline int notify_page_fault(struct pt_regs *regs) 50static inline int __kprobes notify_page_fault(struct pt_regs *regs)
50{ 51{
51 int ret = 0; 52 int ret = 0;
52 53
@@ -240,7 +241,7 @@ void vmalloc_sync_all(void)
240 * 241 *
241 * Handle a fault on the vmalloc or module mapping area 242 * Handle a fault on the vmalloc or module mapping area
242 */ 243 */
243static noinline int vmalloc_fault(unsigned long address) 244static noinline __kprobes int vmalloc_fault(unsigned long address)
244{ 245{
245 unsigned long pgd_paddr; 246 unsigned long pgd_paddr;
246 pmd_t *pmd_k; 247 pmd_t *pmd_k;
@@ -357,7 +358,7 @@ void vmalloc_sync_all(void)
357 * 358 *
358 * This assumes no large pages in there. 359 * This assumes no large pages in there.
359 */ 360 */
360static noinline int vmalloc_fault(unsigned long address) 361static noinline __kprobes int vmalloc_fault(unsigned long address)
361{ 362{
362 pgd_t *pgd, *pgd_ref; 363 pgd_t *pgd, *pgd_ref;
363 pud_t *pud, *pud_ref; 364 pud_t *pud, *pud_ref;
@@ -860,7 +861,7 @@ static int spurious_fault_check(unsigned long error_code, pte_t *pte)
860 * There are no security implications to leaving a stale TLB when 861 * There are no security implications to leaving a stale TLB when
861 * increasing the permissions on a page. 862 * increasing the permissions on a page.
862 */ 863 */
863static noinline int 864static noinline __kprobes int
864spurious_fault(unsigned long error_code, unsigned long address) 865spurious_fault(unsigned long error_code, unsigned long address)
865{ 866{
866 pgd_t *pgd; 867 pgd_t *pgd;
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
new file mode 100644
index 000000000000..1bd006c81564
--- /dev/null
+++ b/arch/x86/tools/Makefile
@@ -0,0 +1,15 @@
1PHONY += posttest
2quiet_cmd_posttest = TEST $@
3 cmd_posttest = $(OBJDUMP) -d -j .text $(objtree)/vmlinux | awk -f $(srctree)/arch/x86/tools/distill.awk | $(obj)/test_get_len $(CONFIG_64BIT)
4
5posttest: $(obj)/test_get_len vmlinux
6 $(call cmd,posttest)
7
8hostprogs-y := test_get_len
9
10# -I needed for generated C source and C source which in the kernel tree.
11HOSTCFLAGS_test_get_len.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/
12
13# Dependancies are also needed.
14$(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
15
diff --git a/arch/x86/tools/distill.awk b/arch/x86/tools/distill.awk
new file mode 100644
index 000000000000..d433619bb866
--- /dev/null
+++ b/arch/x86/tools/distill.awk
@@ -0,0 +1,42 @@
1#!/bin/awk -f
2# Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len
3# Distills the disassembly as follows:
4# - Removes all lines except the disassembled instructions.
5# - For instructions that exceed 1 line (7 bytes), crams all the hex bytes
6# into a single line.
7# - Remove bad(or prefix only) instructions
8
9BEGIN {
10 prev_addr = ""
11 prev_hex = ""
12 prev_mnemonic = ""
13 bad_expr = "(\\(bad\\)|^rex|^.byte|^rep(z|nz)$|^lock$|^es$|^cs$|^ss$|^ds$|^fs$|^gs$|^data(16|32)$|^addr(16|32|64))"
14 fwait_expr = "^9b "
15 fwait_str="9b\tfwait"
16}
17
18/^ *[0-9a-f]+:/ {
19 if (split($0, field, "\t") < 3) {
20 # This is a continuation of the same insn.
21 prev_hex = prev_hex field[2]
22 } else {
23 # Skip bad instructions
24 if (match(prev_mnemonic, bad_expr))
25 prev_addr = ""
26 # Split fwait from other f* instructions
27 if (match(prev_hex, fwait_expr) && prev_mnemonic != "fwait") {
28 printf "%s\t%s\n", prev_addr, fwait_str
29 sub(fwait_expr, "", prev_hex)
30 }
31 if (prev_addr != "")
32 printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic
33 prev_addr = field[1]
34 prev_hex = field[2]
35 prev_mnemonic = field[3]
36 }
37}
38
39END {
40 if (prev_addr != "")
41 printf "%s\t%s\t%s\n", prev_addr, prev_hex, prev_mnemonic
42}
diff --git a/arch/x86/tools/gen-insn-attr-x86.awk b/arch/x86/tools/gen-insn-attr-x86.awk
new file mode 100644
index 000000000000..19ba096b7dd1
--- /dev/null
+++ b/arch/x86/tools/gen-insn-attr-x86.awk
@@ -0,0 +1,334 @@
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 (!match("abc", "[[:lower:]]+"))
10 return "Your awk doesn't support charactor-class."
11 if (sprintf("%x", 0) != "0")
12 return "Your awk has a printf-format problem."
13 return ""
14}
15
16BEGIN {
17 # Implementation error checking
18 awkchecked = check_awk_implement()
19 if (awkchecked != "") {
20 print "Error: " awkchecked > "/dev/stderr"
21 print "Please try to use gawk." > "/dev/stderr"
22 exit 1
23 }
24
25 # Setup generating tables
26 print "/* x86 opcode map generated from x86-opcode-map.txt */"
27 print "/* Do not change this code. */"
28 ggid = 1
29 geid = 1
30
31 opnd_expr = "^[[:alpha:]]"
32 ext_expr = "^\\("
33 sep_expr = "^\\|$"
34 group_expr = "^Grp[[:alnum:]]+"
35
36 imm_expr = "^[IJAO][[:lower:]]"
37 imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
38 imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
39 imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
40 imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
41 imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
42 imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
43 imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
44 imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
45 imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
46 imm_flag["Ob"] = "INAT_MOFFSET"
47 imm_flag["Ov"] = "INAT_MOFFSET"
48
49 modrm_expr = "^([CDEGMNPQRSUVW][[:lower:]]+|NTA|T[012])"
50 force64_expr = "\\([df]64\\)"
51 rex_expr = "^REX(\\.[XRWB]+)*"
52 fpu_expr = "^ESC" # TODO
53
54 lprefix1_expr = "\\(66\\)"
55 delete lptable1
56 lprefix2_expr = "\\(F2\\)"
57 delete lptable2
58 lprefix3_expr = "\\(F3\\)"
59 delete lptable3
60 max_lprefix = 4
61
62 prefix_expr = "\\(Prefix\\)"
63 prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
64 prefix_num["REPNE"] = "INAT_PFX_REPNE"
65 prefix_num["REP/REPE"] = "INAT_PFX_REPE"
66 prefix_num["LOCK"] = "INAT_PFX_LOCK"
67 prefix_num["SEG=CS"] = "INAT_PFX_CS"
68 prefix_num["SEG=DS"] = "INAT_PFX_DS"
69 prefix_num["SEG=ES"] = "INAT_PFX_ES"
70 prefix_num["SEG=FS"] = "INAT_PFX_FS"
71 prefix_num["SEG=GS"] = "INAT_PFX_GS"
72 prefix_num["SEG=SS"] = "INAT_PFX_SS"
73 prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
74
75 delete table
76 delete etable
77 delete gtable
78 eid = -1
79 gid = -1
80}
81
82function semantic_error(msg) {
83 print "Semantic error at " NR ": " msg > "/dev/stderr"
84 exit 1
85}
86
87function debug(msg) {
88 print "DEBUG: " msg
89}
90
91function array_size(arr, i,c) {
92 c = 0
93 for (i in arr)
94 c++
95 return c
96}
97
98/^Table:/ {
99 print "/* " $0 " */"
100}
101
102/^Referrer:/ {
103 if (NF == 1) {
104 # primary opcode table
105 tname = "inat_primary_table"
106 eid = -1
107 } else {
108 # escape opcode table
109 ref = ""
110 for (i = 2; i <= NF; i++)
111 ref = ref $i
112 eid = escape[ref]
113 tname = sprintf("inat_escape_table_%d", eid)
114 }
115}
116
117/^GrpTable:/ {
118 print "/* " $0 " */"
119 if (!($2 in group))
120 semantic_error("No group: " $2 )
121 gid = group[$2]
122 tname = "inat_group_table_" gid
123}
124
125function print_table(tbl,name,fmt,n)
126{
127 print "const insn_attr_t " name " = {"
128 for (i = 0; i < n; i++) {
129 id = sprintf(fmt, i)
130 if (tbl[id])
131 print " [" id "] = " tbl[id] ","
132 }
133 print "};"
134}
135
136/^EndTable/ {
137 if (gid != -1) {
138 # print group tables
139 if (array_size(table) != 0) {
140 print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
141 "0x%x", 8)
142 gtable[gid,0] = tname
143 }
144 if (array_size(lptable1) != 0) {
145 print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
146 "0x%x", 8)
147 gtable[gid,1] = tname "_1"
148 }
149 if (array_size(lptable2) != 0) {
150 print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
151 "0x%x", 8)
152 gtable[gid,2] = tname "_2"
153 }
154 if (array_size(lptable3) != 0) {
155 print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
156 "0x%x", 8)
157 gtable[gid,3] = tname "_3"
158 }
159 } else {
160 # print primary/escaped tables
161 if (array_size(table) != 0) {
162 print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
163 "0x%02x", 256)
164 etable[eid,0] = tname
165 }
166 if (array_size(lptable1) != 0) {
167 print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
168 "0x%02x", 256)
169 etable[eid,1] = tname "_1"
170 }
171 if (array_size(lptable2) != 0) {
172 print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
173 "0x%02x", 256)
174 etable[eid,2] = tname "_2"
175 }
176 if (array_size(lptable3) != 0) {
177 print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
178 "0x%02x", 256)
179 etable[eid,3] = tname "_3"
180 }
181 }
182 print ""
183 delete table
184 delete lptable1
185 delete lptable2
186 delete lptable3
187 gid = -1
188 eid = -1
189}
190
191function add_flags(old,new) {
192 if (old && new)
193 return old " | " new
194 else if (old)
195 return old
196 else
197 return new
198}
199
200# convert operands to flags.
201function convert_operands(opnd, i,imm,mod)
202{
203 imm = null
204 mod = null
205 for (i in opnd) {
206 i = opnd[i]
207 if (match(i, imm_expr) == 1) {
208 if (!imm_flag[i])
209 semantic_error("Unknown imm opnd: " i)
210 if (imm) {
211 if (i != "Ib")
212 semantic_error("Second IMM error")
213 imm = add_flags(imm, "INAT_SCNDIMM")
214 } else
215 imm = imm_flag[i]
216 } else if (match(i, modrm_expr))
217 mod = "INAT_MODRM"
218 }
219 return add_flags(imm, mod)
220}
221
222/^[0-9a-f]+\:/ {
223 if (NR == 1)
224 next
225 # get index
226 idx = "0x" substr($1, 1, index($1,":") - 1)
227 if (idx in table)
228 semantic_error("Redefine " idx " in " tname)
229
230 # check if escaped opcode
231 if ("escape" == $2) {
232 if ($3 != "#")
233 semantic_error("No escaped name")
234 ref = ""
235 for (i = 4; i <= NF; i++)
236 ref = ref $i
237 if (ref in escape)
238 semantic_error("Redefine escape (" ref ")")
239 escape[ref] = geid
240 geid++
241 table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
242 next
243 }
244
245 variant = null
246 # converts
247 i = 2
248 while (i <= NF) {
249 opcode = $(i++)
250 delete opnds
251 ext = null
252 flags = null
253 opnd = null
254 # parse one opcode
255 if (match($i, opnd_expr)) {
256 opnd = $i
257 split($(i++), opnds, ",")
258 flags = convert_operands(opnds)
259 }
260 if (match($i, ext_expr))
261 ext = $(i++)
262 if (match($i, sep_expr))
263 i++
264 else if (i < NF)
265 semantic_error($i " is not a separator")
266
267 # check if group opcode
268 if (match(opcode, group_expr)) {
269 if (!(opcode in group)) {
270 group[opcode] = ggid
271 ggid++
272 }
273 flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
274 }
275 # check force(or default) 64bit
276 if (match(ext, force64_expr))
277 flags = add_flags(flags, "INAT_FORCE64")
278
279 # check REX prefix
280 if (match(opcode, rex_expr))
281 flags = add_flags(flags, "INAT_REXPFX")
282
283 # check coprocessor escape : TODO
284 if (match(opcode, fpu_expr))
285 flags = add_flags(flags, "INAT_MODRM")
286
287 # check prefixes
288 if (match(ext, prefix_expr)) {
289 if (!prefix_num[opcode])
290 semantic_error("Unknown prefix: " opcode)
291 flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
292 }
293 if (length(flags) == 0)
294 continue
295 # check if last prefix
296 if (match(ext, lprefix1_expr)) {
297 lptable1[idx] = add_flags(lptable1[idx],flags)
298 variant = "INAT_VARIANT"
299 } else if (match(ext, lprefix2_expr)) {
300 lptable2[idx] = add_flags(lptable2[idx],flags)
301 variant = "INAT_VARIANT"
302 } else if (match(ext, lprefix3_expr)) {
303 lptable3[idx] = add_flags(lptable3[idx],flags)
304 variant = "INAT_VARIANT"
305 } else {
306 table[idx] = add_flags(table[idx],flags)
307 }
308 }
309 if (variant)
310 table[idx] = add_flags(table[idx],variant)
311}
312
313END {
314 if (awkchecked != "")
315 exit 1
316 # print escape opcode map's array
317 print "/* Escape opcode map array */"
318 print "const insn_attr_t const *inat_escape_tables[INAT_ESC_MAX + 1]" \
319 "[INAT_LPREFIX_MAX + 1] = {"
320 for (i = 0; i < geid; i++)
321 for (j = 0; j < max_lprefix; j++)
322 if (etable[i,j])
323 print " ["i"]["j"] = "etable[i,j]","
324 print "};\n"
325 # print group opcode map's array
326 print "/* Group opcode map array */"
327 print "const insn_attr_t const *inat_group_tables[INAT_GRP_MAX + 1]"\
328 "[INAT_LPREFIX_MAX + 1] = {"
329 for (i = 0; i < ggid; i++)
330 for (j = 0; j < max_lprefix; j++)
331 if (gtable[i,j])
332 print " ["i"]["j"] = "gtable[i,j]","
333 print "};"
334}
diff --git a/arch/x86/tools/test_get_len.c b/arch/x86/tools/test_get_len.c
new file mode 100644
index 000000000000..376d33852191
--- /dev/null
+++ b/arch/x86/tools/test_get_len.c
@@ -0,0 +1,108 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 *
16 * Copyright (C) IBM Corporation, 2009
17 */
18
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <assert.h>
23
24#define unlikely(cond) (cond)
25
26#include <asm/insn.h>
27#include <inat.c>
28#include <insn.c>
29
30/*
31 * Test of instruction analysis in general and insn_get_length() in
32 * particular. See if insn_get_length() and the disassembler agree
33 * on the length of each instruction in an elf disassembly.
34 *
35 * Usage: objdump -d a.out | awk -f distill.awk | ./test_get_len
36 */
37
38const char *prog;
39
40static void usage(void)
41{
42 fprintf(stderr, "Usage: objdump -d a.out | awk -f distill.awk |"
43 " %s [y|n](64bit flag)\n", prog);
44 exit(1);
45}
46
47static void malformed_line(const char *line, int line_nr)
48{
49 fprintf(stderr, "%s: malformed line %d:\n%s", prog, line_nr, line);
50 exit(3);
51}
52
53#define BUFSIZE 256
54
55int main(int argc, char **argv)
56{
57 char line[BUFSIZE];
58 unsigned char insn_buf[16];
59 struct insn insn;
60 int insns = 0;
61 int x86_64 = 0;
62
63 prog = argv[0];
64 if (argc > 2)
65 usage();
66
67 if (argc == 2 && argv[1][0] == 'y')
68 x86_64 = 1;
69
70 while (fgets(line, BUFSIZE, stdin)) {
71 char copy[BUFSIZE], *s, *tab1, *tab2;
72 int nb = 0;
73 unsigned int b;
74
75 insns++;
76 memset(insn_buf, 0, 16);
77 strcpy(copy, line);
78 tab1 = strchr(copy, '\t');
79 if (!tab1)
80 malformed_line(line, insns);
81 s = tab1 + 1;
82 s += strspn(s, " ");
83 tab2 = strchr(s, '\t');
84 if (!tab2)
85 malformed_line(line, insns);
86 *tab2 = '\0'; /* Characters beyond tab2 aren't examined */
87 while (s < tab2) {
88 if (sscanf(s, "%x", &b) == 1) {
89 insn_buf[nb++] = (unsigned char) b;
90 s += 3;
91 } else
92 break;
93 }
94 /* Decode an instruction */
95 insn_init(&insn, insn_buf, x86_64);
96 insn_get_length(&insn);
97 if (insn.length != nb) {
98 fprintf(stderr, "Error: %s", line);
99 fprintf(stderr, "Error: objdump says %d bytes, but "
100 "insn_get_length() says %d (attr:%x)\n", nb,
101 insn.length, insn.attr);
102 exit(2);
103 }
104 }
105 fprintf(stderr, "Succeed: decoded and checked %d instructions\n",
106 insns);
107 return 0;
108}