diff options
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/Kconfig.debug | 9 | ||||
-rw-r--r-- | arch/x86/Makefile | 3 | ||||
-rw-r--r-- | arch/x86/include/asm/inat.h | 188 | ||||
-rw-r--r-- | arch/x86/include/asm/inat_types.h | 29 | ||||
-rw-r--r-- | arch/x86/include/asm/insn.h | 143 | ||||
-rw-r--r-- | arch/x86/include/asm/ptrace.h | 62 | ||||
-rw-r--r-- | arch/x86/kernel/entry_32.S | 24 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 8 | ||||
-rw-r--r-- | arch/x86/kernel/kprobes.c | 234 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 112 | ||||
-rw-r--r-- | arch/x86/lib/Makefile | 13 | ||||
-rw-r--r-- | arch/x86/lib/inat.c | 78 | ||||
-rw-r--r-- | arch/x86/lib/insn.c | 464 | ||||
-rw-r--r-- | arch/x86/lib/x86-opcode-map.txt | 835 | ||||
-rw-r--r-- | arch/x86/mm/fault.c | 11 | ||||
-rw-r--r-- | arch/x86/tools/Makefile | 15 | ||||
-rw-r--r-- | arch/x86/tools/distill.awk | 42 | ||||
-rw-r--r-- | arch/x86/tools/gen-insn-attr-x86.awk | 334 | ||||
-rw-r--r-- | arch/x86/tools/test_get_len.c | 108 |
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 | |||
186 | config HAVE_MMIOTRACE_SUPPORT | 186 | config HAVE_MMIOTRACE_SUPPORT |
187 | def_bool y | 187 | def_bool y |
188 | 188 | ||
189 | config 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 | |||
156 | KBUILD_IMAGE := $(boot)/bzImage | 156 | KBUILD_IMAGE := $(boot)/bzImage |
157 | 157 | ||
158 | bzImage: vmlinux | 158 | bzImage: vmlinux |
159 | ifeq ($(CONFIG_X86_DECODER_SELFTEST),y) | ||
160 | $(Q)$(MAKE) $(build)=arch/x86/tools posttest | ||
161 | endif | ||
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 */ | ||
91 | extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); | ||
92 | extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, | ||
93 | insn_byte_t last_pfx, | ||
94 | insn_attr_t esc_attr); | ||
95 | extern 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 */ | ||
100 | static inline int inat_is_prefix(insn_attr_t attr) | ||
101 | { | ||
102 | return attr & INAT_PFX_MASK; | ||
103 | } | ||
104 | |||
105 | static inline int inat_is_address_size_prefix(insn_attr_t attr) | ||
106 | { | ||
107 | return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; | ||
108 | } | ||
109 | |||
110 | static inline int inat_is_operand_size_prefix(insn_attr_t attr) | ||
111 | { | ||
112 | return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; | ||
113 | } | ||
114 | |||
115 | static 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 | |||
123 | static inline int inat_is_escape(insn_attr_t attr) | ||
124 | { | ||
125 | return attr & INAT_ESC_MASK; | ||
126 | } | ||
127 | |||
128 | static inline int inat_escape_id(insn_attr_t attr) | ||
129 | { | ||
130 | return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; | ||
131 | } | ||
132 | |||
133 | static inline int inat_is_group(insn_attr_t attr) | ||
134 | { | ||
135 | return attr & INAT_GRP_MASK; | ||
136 | } | ||
137 | |||
138 | static inline int inat_group_id(insn_attr_t attr) | ||
139 | { | ||
140 | return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; | ||
141 | } | ||
142 | |||
143 | static inline int inat_group_common_attribute(insn_attr_t attr) | ||
144 | { | ||
145 | return attr & ~INAT_GRP_MASK; | ||
146 | } | ||
147 | |||
148 | static inline int inat_has_immediate(insn_attr_t attr) | ||
149 | { | ||
150 | return attr & INAT_IMM_MASK; | ||
151 | } | ||
152 | |||
153 | static inline int inat_immediate_size(insn_attr_t attr) | ||
154 | { | ||
155 | return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; | ||
156 | } | ||
157 | |||
158 | static inline int inat_is_rex_prefix(insn_attr_t attr) | ||
159 | { | ||
160 | return attr & INAT_REXPFX; | ||
161 | } | ||
162 | |||
163 | static inline int inat_has_modrm(insn_attr_t attr) | ||
164 | { | ||
165 | return attr & INAT_MODRM; | ||
166 | } | ||
167 | |||
168 | static inline int inat_is_force64(insn_attr_t attr) | ||
169 | { | ||
170 | return attr & INAT_FORCE64; | ||
171 | } | ||
172 | |||
173 | static inline int inat_has_second_immediate(insn_attr_t attr) | ||
174 | { | ||
175 | return attr & INAT_SCNDIMM; | ||
176 | } | ||
177 | |||
178 | static inline int inat_has_moffset(insn_attr_t attr) | ||
179 | { | ||
180 | return attr & INAT_MOFFSET; | ||
181 | } | ||
182 | |||
183 | static 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 */ | ||
25 | typedef unsigned int insn_attr_t; | ||
26 | typedef unsigned char insn_byte_t; | ||
27 | typedef 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 | |||
26 | struct insn_field { | ||
27 | union { | ||
28 | insn_value_t value; | ||
29 | insn_byte_t bytes[4]; | ||
30 | }; | ||
31 | /* !0 if we've run insn_get_xxx() for this field */ | ||
32 | unsigned char got; | ||
33 | unsigned char nbytes; | ||
34 | }; | ||
35 | |||
36 | struct insn { | ||
37 | struct insn_field prefixes; /* | ||
38 | * Prefixes | ||
39 | * prefixes.bytes[3]: last prefix | ||
40 | */ | ||
41 | struct insn_field rex_prefix; /* REX prefix */ | ||
42 | struct insn_field 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 */ | ||
84 | static inline insn_byte_t insn_last_prefix(struct insn *insn) | ||
85 | { | ||
86 | return insn->prefixes.bytes[3]; | ||
87 | } | ||
88 | |||
89 | extern void insn_init(struct insn *insn, const void *kaddr, int x86_64); | ||
90 | extern void insn_get_prefixes(struct insn *insn); | ||
91 | extern void insn_get_opcode(struct insn *insn); | ||
92 | extern void insn_get_modrm(struct insn *insn); | ||
93 | extern void insn_get_sib(struct insn *insn); | ||
94 | extern void insn_get_displacement(struct insn *insn); | ||
95 | extern void insn_get_immediate(struct insn *insn); | ||
96 | extern void insn_get_length(struct insn *insn); | ||
97 | |||
98 | /* Attribute will be determined after getting ModRM (for opcode groups) */ | ||
99 | static inline void insn_get_attribute(struct insn *insn) | ||
100 | { | ||
101 | insn_get_modrm(insn); | ||
102 | } | ||
103 | |||
104 | /* Instruction uses RIP-relative addressing */ | ||
105 | extern int insn_rip_relative(struct insn *insn); | ||
106 | |||
107 | /* Init insn for kernel text */ | ||
108 | static 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 */ | ||
118 | static inline int insn_offset_rex_prefix(struct insn *insn) | ||
119 | { | ||
120 | return insn->prefixes.nbytes; | ||
121 | } | ||
122 | static inline int insn_offset_opcode(struct insn *insn) | ||
123 | { | ||
124 | return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; | ||
125 | } | ||
126 | static inline int insn_offset_modrm(struct insn *insn) | ||
127 | { | ||
128 | return insn_offset_opcode(insn) + insn->opcode.nbytes; | ||
129 | } | ||
130 | static inline int insn_offset_sib(struct insn *insn) | ||
131 | { | ||
132 | return insn_offset_modrm(insn) + insn->modrm.nbytes; | ||
133 | } | ||
134 | static inline int insn_offset_displacement(struct insn *insn) | ||
135 | { | ||
136 | return insn_offset_sib(insn) + insn->sib.nbytes; | ||
137 | } | ||
138 | static 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 */ | ||
221 | extern int regs_query_register_offset(const char *name); | ||
222 | extern 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 | */ | ||
234 | static 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 | */ | ||
250 | static 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 | */ | ||
266 | static 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 */ | ||
278 | extern 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) | |||
334 | END(ret_from_fork) | 334 | END(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: | |||
383 | END(resume_kernel) | 387 | END(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 |
514 | ENDPROC(ia32_sysenter_target) | 522 | ENDPROC(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 |
517 | ENTRY(system_call) | 529 | ENTRY(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 |
706 | END(syscall_badsys) | 718 | END(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: | |||
814 | ENDPROC(common_interrupt) | 830 | ENDPROC(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) \ |
818 | ENTRY(name) \ | 838 | ENTRY(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 |
982 | END(spurious_interrupt_bug) | 1002 | END(spurious_interrupt_bug) |
1003 | /* | ||
1004 | * End of kprobes section | ||
1005 | */ | ||
1006 | .popsection | ||
983 | 1007 | ||
984 | ENTRY(kernel_thread_helper) | 1008 | ENTRY(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 |
943 | END(common_interrupt) | 947 | END(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 | ||
58 | void jprobe_return_end(void); | 60 | void 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 | }; |
109 | static 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 | }; | ||
131 | static 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 | ||
155 | struct kretprobe_blackpoint kretprobe_blacklist[] = { | 113 | struct 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. */ | ||
206 | static 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 */ | ||
232 | static char __dummy_buf[KSYM_NAME_LEN]; | ||
233 | |||
234 | /* Check if paddr is at an instruction boundary */ | ||
235 | static 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) | |||
277 | static void __kprobes fix_riprel(struct kprobe *p) | 304 | static 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 | ||
360 | int __kprobes arch_prepare_kprobe(struct kprobe *p) | 349 | int __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 | ||
52 | struct 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 | |||
60 | static 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 | */ | ||
100 | int 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 | */ | ||
116 | const 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 | |||
125 | static 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 | */ | ||
150 | unsigned 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 | ||
5 | inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk | ||
6 | inat_tables_maps = $(srctree)/arch/x86/lib/x86-opcode-map.txt | ||
7 | quiet_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 | |||
15 | clean-files := inat-tables.c | ||
16 | |||
5 | obj-$(CONFIG_SMP) := msr.o | 17 | obj-$(CONFIG_SMP) := msr.o |
6 | 18 | ||
7 | lib-y := delay.o | 19 | lib-y := delay.o |
8 | lib-y += thunk_$(BITS).o | 20 | lib-y += thunk_$(BITS).o |
9 | lib-y += usercopy_$(BITS).o getuser.o putuser.o | 21 | lib-y += usercopy_$(BITS).o getuser.o putuser.o |
10 | lib-y += memcpy_$(BITS).o | 22 | lib-y += memcpy_$(BITS).o |
23 | lib-y += insn.o inat.o | ||
11 | 24 | ||
12 | obj-y += msr-reg.o msr-reg-export.o | 25 | obj-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 */ | ||
27 | insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) | ||
28 | { | ||
29 | return inat_primary_table[opcode]; | ||
30 | } | ||
31 | |||
32 | insn_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 | |||
55 | insn_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 | */ | ||
37 | void 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 | */ | ||
58 | void 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 | } | ||
91 | found: | ||
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 | */ | ||
137 | void 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 | */ | ||
169 | void 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 | */ | ||
202 | int 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 | */ | ||
224 | void 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 | */ | ||
252 | void 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 | } | ||
300 | out: | ||
301 | insn->displacement.got = 1; | ||
302 | } | ||
303 | |||
304 | /* Decode moffset16/32/64 */ | ||
305 | static 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) */ | ||
327 | static 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) */ | ||
343 | static 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) */ | ||
365 | static 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 | */ | ||
394 | void 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 | } | ||
445 | done: | ||
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 | */ | ||
456 | void 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 | |||
17 | Table: one byte opcode | ||
18 | Referrer: | ||
19 | # 0x00 - 0x0f | ||
20 | 00: ADD Eb,Gb | ||
21 | 01: ADD Ev,Gv | ||
22 | 02: ADD Gb,Eb | ||
23 | 03: ADD Gv,Ev | ||
24 | 04: ADD AL,Ib | ||
25 | 05: ADD rAX,Iz | ||
26 | 06: PUSH ES (i64) | ||
27 | 07: POP ES (i64) | ||
28 | 08: OR Eb,Gb | ||
29 | 09: OR Ev,Gv | ||
30 | 0a: OR Gb,Eb | ||
31 | 0b: OR Gv,Ev | ||
32 | 0c: OR AL,Ib | ||
33 | 0d: OR rAX,Iz | ||
34 | 0e: PUSH CS (i64) | ||
35 | 0f: escape # 2-byte escape | ||
36 | # 0x10 - 0x1f | ||
37 | 10: ADC Eb,Gb | ||
38 | 11: ADC Ev,Gv | ||
39 | 12: ADC Gb,Eb | ||
40 | 13: ADC Gv,Ev | ||
41 | 14: ADC AL,Ib | ||
42 | 15: ADC rAX,Iz | ||
43 | 16: PUSH SS (i64) | ||
44 | 17: POP SS (i64) | ||
45 | 18: SBB Eb,Gb | ||
46 | 19: SBB Ev,Gv | ||
47 | 1a: SBB Gb,Eb | ||
48 | 1b: SBB Gv,Ev | ||
49 | 1c: SBB AL,Ib | ||
50 | 1d: SBB rAX,Iz | ||
51 | 1e: PUSH DS (i64) | ||
52 | 1f: POP DS (i64) | ||
53 | # 0x20 - 0x2f | ||
54 | 20: AND Eb,Gb | ||
55 | 21: AND Ev,Gv | ||
56 | 22: AND Gb,Eb | ||
57 | 23: AND Gv,Ev | ||
58 | 24: AND AL,Ib | ||
59 | 25: AND rAx,Iz | ||
60 | 26: SEG=ES (Prefix) | ||
61 | 27: DAA (i64) | ||
62 | 28: SUB Eb,Gb | ||
63 | 29: SUB Ev,Gv | ||
64 | 2a: SUB Gb,Eb | ||
65 | 2b: SUB Gv,Ev | ||
66 | 2c: SUB AL,Ib | ||
67 | 2d: SUB rAX,Iz | ||
68 | 2e: SEG=CS (Prefix) | ||
69 | 2f: DAS (i64) | ||
70 | # 0x30 - 0x3f | ||
71 | 30: XOR Eb,Gb | ||
72 | 31: XOR Ev,Gv | ||
73 | 32: XOR Gb,Eb | ||
74 | 33: XOR Gv,Ev | ||
75 | 34: XOR AL,Ib | ||
76 | 35: XOR rAX,Iz | ||
77 | 36: SEG=SS (Prefix) | ||
78 | 37: AAA (i64) | ||
79 | 38: CMP Eb,Gb | ||
80 | 39: CMP Ev,Gv | ||
81 | 3a: CMP Gb,Eb | ||
82 | 3b: CMP Gv,Ev | ||
83 | 3c: CMP AL,Ib | ||
84 | 3d: CMP rAX,Iz | ||
85 | 3e: SEG=DS (Prefix) | ||
86 | 3f: AAS (i64) | ||
87 | # 0x40 - 0x4f | ||
88 | 40: INC eAX (i64) | REX (o64) | ||
89 | 41: INC eCX (i64) | REX.B (o64) | ||
90 | 42: INC eDX (i64) | REX.X (o64) | ||
91 | 43: INC eBX (i64) | REX.XB (o64) | ||
92 | 44: INC eSP (i64) | REX.R (o64) | ||
93 | 45: INC eBP (i64) | REX.RB (o64) | ||
94 | 46: INC eSI (i64) | REX.RX (o64) | ||
95 | 47: INC eDI (i64) | REX.RXB (o64) | ||
96 | 48: DEC eAX (i64) | REX.W (o64) | ||
97 | 49: DEC eCX (i64) | REX.WB (o64) | ||
98 | 4a: DEC eDX (i64) | REX.WX (o64) | ||
99 | 4b: DEC eBX (i64) | REX.WXB (o64) | ||
100 | 4c: DEC eSP (i64) | REX.WR (o64) | ||
101 | 4d: DEC eBP (i64) | REX.WRB (o64) | ||
102 | 4e: DEC eSI (i64) | REX.WRX (o64) | ||
103 | 4f: DEC eDI (i64) | REX.WRXB (o64) | ||
104 | # 0x50 - 0x5f | ||
105 | 50: PUSH rAX/r8 (d64) | ||
106 | 51: PUSH rCX/r9 (d64) | ||
107 | 52: PUSH rDX/r10 (d64) | ||
108 | 53: PUSH rBX/r11 (d64) | ||
109 | 54: PUSH rSP/r12 (d64) | ||
110 | 55: PUSH rBP/r13 (d64) | ||
111 | 56: PUSH rSI/r14 (d64) | ||
112 | 57: PUSH rDI/r15 (d64) | ||
113 | 58: POP rAX/r8 (d64) | ||
114 | 59: POP rCX/r9 (d64) | ||
115 | 5a: POP rDX/r10 (d64) | ||
116 | 5b: POP rBX/r11 (d64) | ||
117 | 5c: POP rSP/r12 (d64) | ||
118 | 5d: POP rBP/r13 (d64) | ||
119 | 5e: POP rSI/r14 (d64) | ||
120 | 5f: POP rDI/r15 (d64) | ||
121 | # 0x60 - 0x6f | ||
122 | 60: PUSHA/PUSHAD (i64) | ||
123 | 61: POPA/POPAD (i64) | ||
124 | 62: BOUND Gv,Ma (i64) | ||
125 | 63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) | ||
126 | 64: SEG=FS (Prefix) | ||
127 | 65: SEG=GS (Prefix) | ||
128 | 66: Operand-Size (Prefix) | ||
129 | 67: Address-Size (Prefix) | ||
130 | 68: PUSH Iz (d64) | ||
131 | 69: IMUL Gv,Ev,Iz | ||
132 | 6a: PUSH Ib (d64) | ||
133 | 6b: IMUL Gv,Ev,Ib | ||
134 | 6c: INS/INSB Yb,DX | ||
135 | 6d: INS/INSW/INSD Yz,DX | ||
136 | 6e: OUTS/OUTSB DX,Xb | ||
137 | 6f: OUTS/OUTSW/OUTSD DX,Xz | ||
138 | # 0x70 - 0x7f | ||
139 | 70: JO Jb | ||
140 | 71: JNO Jb | ||
141 | 72: JB/JNAE/JC Jb | ||
142 | 73: JNB/JAE/JNC Jb | ||
143 | 74: JZ/JE Jb | ||
144 | 75: JNZ/JNE Jb | ||
145 | 76: JBE/JNA Jb | ||
146 | 77: JNBE/JA Jb | ||
147 | 78: JS Jb | ||
148 | 79: JNS Jb | ||
149 | 7a: JP/JPE Jb | ||
150 | 7b: JNP/JPO Jb | ||
151 | 7c: JL/JNGE Jb | ||
152 | 7d: JNL/JGE Jb | ||
153 | 7e: JLE/JNG Jb | ||
154 | 7f: JNLE/JG Jb | ||
155 | # 0x80 - 0x8f | ||
156 | 80: Grp1 Eb,Ib (1A) | ||
157 | 81: Grp1 Ev,Iz (1A) | ||
158 | 82: Grp1 Eb,Ib (1A),(i64) | ||
159 | 83: Grp1 Ev,Ib (1A) | ||
160 | 84: TEST Eb,Gb | ||
161 | 85: TEST Ev,Gv | ||
162 | 86: XCHG Eb,Gb | ||
163 | 87: XCHG Ev,Gv | ||
164 | 88: MOV Eb,Gb | ||
165 | 89: MOV Ev,Gv | ||
166 | 8a: MOV Gb,Eb | ||
167 | 8b: MOV Gv,Ev | ||
168 | 8c: MOV Ev,Sw | ||
169 | 8d: LEA Gv,M | ||
170 | 8e: MOV Sw,Ew | ||
171 | 8f: Grp1A (1A) | POP Ev (d64) | ||
172 | # 0x90 - 0x9f | ||
173 | 90: NOP | PAUSE (F3) | XCHG r8,rAX | ||
174 | 91: XCHG rCX/r9,rAX | ||
175 | 92: XCHG rDX/r10,rAX | ||
176 | 93: XCHG rBX/r11,rAX | ||
177 | 94: XCHG rSP/r12,rAX | ||
178 | 95: XCHG rBP/r13,rAX | ||
179 | 96: XCHG rSI/r14,rAX | ||
180 | 97: XCHG rDI/r15,rAX | ||
181 | 98: CBW/CWDE/CDQE | ||
182 | 99: CWD/CDQ/CQO | ||
183 | 9a: CALLF Ap (i64) | ||
184 | 9b: FWAIT/WAIT | ||
185 | 9c: PUSHF/D/Q Fv (d64) | ||
186 | 9d: POPF/D/Q Fv (d64) | ||
187 | 9e: SAHF | ||
188 | 9f: LAHF | ||
189 | # 0xa0 - 0xaf | ||
190 | a0: MOV AL,Ob | ||
191 | a1: MOV rAX,Ov | ||
192 | a2: MOV Ob,AL | ||
193 | a3: MOV Ov,rAX | ||
194 | a4: MOVS/B Xb,Yb | ||
195 | a5: MOVS/W/D/Q Xv,Yv | ||
196 | a6: CMPS/B Xb,Yb | ||
197 | a7: CMPS/W/D Xv,Yv | ||
198 | a8: TEST AL,Ib | ||
199 | a9: TEST rAX,Iz | ||
200 | aa: STOS/B Yb,AL | ||
201 | ab: STOS/W/D/Q Yv,rAX | ||
202 | ac: LODS/B AL,Xb | ||
203 | ad: LODS/W/D/Q rAX,Xv | ||
204 | ae: SCAS/B AL,Yb | ||
205 | af: SCAS/W/D/Q rAX,Xv | ||
206 | # 0xb0 - 0xbf | ||
207 | b0: MOV AL/R8L,Ib | ||
208 | b1: MOV CL/R9L,Ib | ||
209 | b2: MOV DL/R10L,Ib | ||
210 | b3: MOV BL/R11L,Ib | ||
211 | b4: MOV AH/R12L,Ib | ||
212 | b5: MOV CH/R13L,Ib | ||
213 | b6: MOV DH/R14L,Ib | ||
214 | b7: MOV BH/R15L,Ib | ||
215 | b8: MOV rAX/r8,Iv | ||
216 | b9: MOV rCX/r9,Iv | ||
217 | ba: MOV rDX/r10,Iv | ||
218 | bb: MOV rBX/r11,Iv | ||
219 | bc: MOV rSP/r12,Iv | ||
220 | bd: MOV rBP/r13,Iv | ||
221 | be: MOV rSI/r14,Iv | ||
222 | bf: MOV rDI/r15,Iv | ||
223 | # 0xc0 - 0xcf | ||
224 | c0: Grp2 Eb,Ib (1A) | ||
225 | c1: Grp2 Ev,Ib (1A) | ||
226 | c2: RETN Iw (f64) | ||
227 | c3: RETN | ||
228 | c4: LES Gz,Mp (i64) | ||
229 | c5: LDS Gz,Mp (i64) | ||
230 | c6: Grp11 Eb,Ib (1A) | ||
231 | c7: Grp11 Ev,Iz (1A) | ||
232 | c8: ENTER Iw,Ib | ||
233 | c9: LEAVE (d64) | ||
234 | ca: RETF Iw | ||
235 | cb: RETF | ||
236 | cc: INT3 | ||
237 | cd: INT Ib | ||
238 | ce: INTO (i64) | ||
239 | cf: IRET/D/Q | ||
240 | # 0xd0 - 0xdf | ||
241 | d0: Grp2 Eb,1 (1A) | ||
242 | d1: Grp2 Ev,1 (1A) | ||
243 | d2: Grp2 Eb,CL (1A) | ||
244 | d3: Grp2 Ev,CL (1A) | ||
245 | d4: AAM Ib (i64) | ||
246 | d5: AAD Ib (i64) | ||
247 | d6: | ||
248 | d7: XLAT/XLATB | ||
249 | d8: ESC | ||
250 | d9: ESC | ||
251 | da: ESC | ||
252 | db: ESC | ||
253 | dc: ESC | ||
254 | dd: ESC | ||
255 | de: ESC | ||
256 | df: ESC | ||
257 | # 0xe0 - 0xef | ||
258 | e0: LOOPNE/LOOPNZ Jb (f64) | ||
259 | e1: LOOPE/LOOPZ Jb (f64) | ||
260 | e2: LOOP Jb (f64) | ||
261 | e3: JrCXZ Jb (f64) | ||
262 | e4: IN AL,Ib | ||
263 | e5: IN eAX,Ib | ||
264 | e6: OUT Ib,AL | ||
265 | e7: OUT Ib,eAX | ||
266 | e8: CALL Jz (f64) | ||
267 | e9: JMP-near Jz (f64) | ||
268 | ea: JMP-far Ap (i64) | ||
269 | eb: JMP-short Jb (f64) | ||
270 | ec: IN AL,DX | ||
271 | ed: IN eAX,DX | ||
272 | ee: OUT DX,AL | ||
273 | ef: OUT DX,eAX | ||
274 | # 0xf0 - 0xff | ||
275 | f0: LOCK (Prefix) | ||
276 | f1: | ||
277 | f2: REPNE (Prefix) | ||
278 | f3: REP/REPE (Prefix) | ||
279 | f4: HLT | ||
280 | f5: CMC | ||
281 | f6: Grp3_1 Eb (1A) | ||
282 | f7: Grp3_2 Ev (1A) | ||
283 | f8: CLC | ||
284 | f9: STC | ||
285 | fa: CLI | ||
286 | fb: STI | ||
287 | fc: CLD | ||
288 | fd: STD | ||
289 | fe: Grp4 (1A) | ||
290 | ff: Grp5 (1A) | ||
291 | EndTable | ||
292 | |||
293 | Table: 2-byte opcode # First Byte is 0x0f | ||
294 | Referrer: 2-byte escape | ||
295 | # 0x0f 0x00-0x0f | ||
296 | 00: Grp6 (1A) | ||
297 | 01: Grp7 (1A) | ||
298 | 02: LAR Gv,Ew | ||
299 | 03: LSL Gv,Ew | ||
300 | 04: | ||
301 | 05: SYSCALL (o64) | ||
302 | 06: CLTS | ||
303 | 07: SYSRET (o64) | ||
304 | 08: INVD | ||
305 | 09: WBINVD | ||
306 | 0a: | ||
307 | 0b: UD2 (1B) | ||
308 | 0c: | ||
309 | 0d: NOP Ev | GrpP | ||
310 | 0e: FEMMS | ||
311 | # 3DNow! uses the last imm byte as opcode extension. | ||
312 | 0f: 3DNow! Pq,Qq,Ib | ||
313 | # 0x0f 0x10-0x1f | ||
314 | 10: movups Vps,Wps | movss Vss,Wss (F3) | movupd Vpd,Wpd (66) | movsd Vsd,Wsd (F2) | ||
315 | 11: movups Wps,Vps | movss Wss,Vss (F3) | movupd Wpd,Vpd (66) | movsd Wsd,Vsd (F2) | ||
316 | 12: movlps Vq,Mq | movlpd Vq,Mq (66) | movhlps Vq,Uq | movddup Vq,Wq (F2) | movsldup Vq,Wq (F3) | ||
317 | 13: mpvlps Mq,Vq | movlpd Mq,Vq (66) | ||
318 | 14: unpcklps Vps,Wq | unpcklpd Vpd,Wq (66) | ||
319 | 15: unpckhps Vps,Wq | unpckhpd Vpd,Wq (66) | ||
320 | 16: movhps Vq,Mq | movhpd Vq,Mq (66) | movlsps Vq,Uq | movshdup Vq,Wq (F3) | ||
321 | 17: movhps Mq,Vq | movhpd Mq,Vq (66) | ||
322 | 18: Grp16 (1A) | ||
323 | 19: | ||
324 | 1a: | ||
325 | 1b: | ||
326 | 1c: | ||
327 | 1d: | ||
328 | 1e: | ||
329 | 1f: NOP Ev | ||
330 | # 0x0f 0x20-0x2f | ||
331 | 20: MOV Rd,Cd | ||
332 | 21: MOV Rd,Dd | ||
333 | 22: MOV Cd,Rd | ||
334 | 23: MOV Dd,Rd | ||
335 | 24: | ||
336 | 25: | ||
337 | 26: | ||
338 | 27: | ||
339 | 28: movaps Vps,Wps | movapd Vpd,Wpd (66) | ||
340 | 29: movaps Wps,Vps | movapd Wpd,Vpd (66) | ||
341 | 2a: cvtpi2ps Vps,Qpi | cvtsi2ss Vss,Ed/q (F3) | cvtpi2pd Vpd,Qpi (66) | cvtsi2sd Vsd,Ed/q (F2) | ||
342 | 2b: movntps Mps,Vps | movntpd Mpd,Vpd (66) | ||
343 | 2c: cvttps2pi Ppi,Wps | cvttss2si Gd/q,Wss (F3) | cvttpd2pi Ppi,Wpd (66) | cvttsd2si Gd/q,Wsd (F2) | ||
344 | 2d: cvtps2pi Ppi,Wps | cvtss2si Gd/q,Wss (F3) | cvtpd2pi Qpi,Wpd (66) | cvtsd2si Gd/q,Wsd (F2) | ||
345 | 2e: ucomiss Vss,Wss | ucomisd Vsd,Wsd (66) | ||
346 | 2f: comiss Vss,Wss | comisd Vsd,Wsd (66) | ||
347 | # 0x0f 0x30-0x3f | ||
348 | 30: WRMSR | ||
349 | 31: RDTSC | ||
350 | 32: RDMSR | ||
351 | 33: RDPMC | ||
352 | 34: SYSENTER | ||
353 | 35: SYSEXIT | ||
354 | 36: | ||
355 | 37: GETSEC | ||
356 | 38: escape # 3-byte escape 1 | ||
357 | 39: | ||
358 | 3a: escape # 3-byte escape 2 | ||
359 | 3b: | ||
360 | 3c: | ||
361 | 3d: | ||
362 | 3e: | ||
363 | 3f: | ||
364 | # 0x0f 0x40-0x4f | ||
365 | 40: CMOVO Gv,Ev | ||
366 | 41: CMOVNO Gv,Ev | ||
367 | 42: CMOVB/C/NAE Gv,Ev | ||
368 | 43: CMOVAE/NB/NC Gv,Ev | ||
369 | 44: CMOVE/Z Gv,Ev | ||
370 | 45: CMOVNE/NZ Gv,Ev | ||
371 | 46: CMOVBE/NA Gv,Ev | ||
372 | 47: CMOVA/NBE Gv,Ev | ||
373 | 48: CMOVS Gv,Ev | ||
374 | 49: CMOVNS Gv,Ev | ||
375 | 4a: CMOVP/PE Gv,Ev | ||
376 | 4b: CMOVNP/PO Gv,Ev | ||
377 | 4c: CMOVL/NGE Gv,Ev | ||
378 | 4d: CMOVNL/GE Gv,Ev | ||
379 | 4e: CMOVLE/NG Gv,Ev | ||
380 | 4f: CMOVNLE/G Gv,Ev | ||
381 | # 0x0f 0x50-0x5f | ||
382 | 50: movmskps Gd/q,Ups | movmskpd Gd/q,Upd (66) | ||
383 | 51: sqrtps Vps,Wps | sqrtss Vss,Wss (F3) | sqrtpd Vpd,Wpd (66) | sqrtsd Vsd,Wsd (F2) | ||
384 | 52: rsqrtps Vps,Wps | rsqrtss Vss,Wss (F3) | ||
385 | 53: rcpps Vps,Wps | rcpss Vss,Wss (F3) | ||
386 | 54: andps Vps,Wps | andpd Vpd,Wpd (66) | ||
387 | 55: andnps Vps,Wps | andnpd Vpd,Wpd (66) | ||
388 | 56: orps Vps,Wps | orpd Vpd,Wpd (66) | ||
389 | 57: xorps Vps,Wps | xorpd Vpd,Wpd (66) | ||
390 | 58: addps Vps,Wps | addss Vss,Wss (F3) | addpd Vpd,Wpd (66) | addsd Vsd,Wsd (F2) | ||
391 | 59: mulps Vps,Wps | mulss Vss,Wss (F3) | mulpd Vpd,Wpd (66) | mulsd Vsd,Wsd (F2) | ||
392 | 5a: cvtps2pd Vpd,Wps | cvtss2sd Vsd,Wss (F3) | cvtpd2ps Vps,Wpd (66) | cvtsd2ss Vsd,Wsd (F2) | ||
393 | 5b: cvtdq2ps Vps,Wdq | cvtps2dq Vdq,Wps (66) | cvttps2dq Vdq,Wps (F3) | ||
394 | 5c: subps Vps,Wps | subss Vss,Wss (F3) | subpd Vpd,Wpd (66) | subsd Vsd,Wsd (F2) | ||
395 | 5d: minps Vps,Wps | minss Vss,Wss (F3) | minpd Vpd,Wpd (66) | minsd Vsd,Wsd (F2) | ||
396 | 5e: divps Vps,Wps | divss Vss,Wss (F3) | divpd Vpd,Wpd (66) | divsd Vsd,Wsd (F2) | ||
397 | 5f: maxps Vps,Wps | maxss Vss,Wss (F3) | maxpd Vpd,Wpd (66) | maxsd Vsd,Wsd (F2) | ||
398 | # 0x0f 0x60-0x6f | ||
399 | 60: punpcklbw Pq,Qd | punpcklbw Vdq,Wdq (66) | ||
400 | 61: punpcklwd Pq,Qd | punpcklwd Vdq,Wdq (66) | ||
401 | 62: punpckldq Pq,Qd | punpckldq Vdq,Wdq (66) | ||
402 | 63: packsswb Pq,Qq | packsswb Vdq,Wdq (66) | ||
403 | 64: pcmpgtb Pq,Qq | pcmpgtb Vdq,Wdq (66) | ||
404 | 65: pcmpgtw Pq,Qq | pcmpgtw(66) Vdq,Wdq | ||
405 | 66: pcmpgtd Pq,Qq | pcmpgtd Vdq,Wdq (66) | ||
406 | 67: packuswb Pq,Qq | packuswb(66) Vdq,Wdq | ||
407 | 68: punpckhbw Pq,Qd | punpckhbw Vdq,Wdq (66) | ||
408 | 69: punpckhwd Pq,Qd | punpckhwd Vdq,Wdq (66) | ||
409 | 6a: punpckhdq Pq,Qd | punpckhdq Vdq,Wdq (66) | ||
410 | 6b: packssdw Pq,Qd | packssdw Vdq,Wdq (66) | ||
411 | 6c: punpcklqdq Vdq,Wdq (66) | ||
412 | 6d: punpckhqdq Vdq,Wdq (66) | ||
413 | 6e: movd/q/ Pd,Ed/q | movd/q Vdq,Ed/q (66) | ||
414 | 6f: movq Pq,Qq | movdqa Vdq,Wdq (66) | movdqu Vdq,Wdq (F3) | ||
415 | # 0x0f 0x70-0x7f | ||
416 | 70: pshufw Pq,Qq,Ib | pshufd Vdq,Wdq,Ib (66) | pshufhw Vdq,Wdq,Ib (F3) | pshuflw VdqWdq,Ib (F2) | ||
417 | 71: Grp12 (1A) | ||
418 | 72: Grp13 (1A) | ||
419 | 73: Grp14 (1A) | ||
420 | 74: pcmpeqb Pq,Qq | pcmpeqb Vdq,Wdq (66) | ||
421 | 75: pcmpeqw Pq,Qq | pcmpeqw Vdq,Wdq (66) | ||
422 | 76: pcmpeqd Pq,Qq | pcmpeqd Vdq,Wdq (66) | ||
423 | 77: emms | ||
424 | 78: VMREAD Ed/q,Gd/q | ||
425 | 79: VMWRITE Gd/q,Ed/q | ||
426 | 7a: | ||
427 | 7b: | ||
428 | 7c: haddps(F2) Vps,Wps | haddpd(66) Vpd,Wpd | ||
429 | 7d: hsubps(F2) Vps,Wps | hsubpd(66) Vpd,Wpd | ||
430 | 7e: movd/q Ed/q,Pd | movd/q Ed/q,Vdq (66) | movq Vq,Wq (F3) | ||
431 | 7f: movq Qq,Pq | movdqa Wdq,Vdq (66) | movdqu Wdq,Vdq (F3) | ||
432 | # 0x0f 0x80-0x8f | ||
433 | 80: JO Jz (f64) | ||
434 | 81: JNO Jz (f64) | ||
435 | 82: JB/JNAE/JC Jz (f64) | ||
436 | 83: JNB/JAE/JNC Jz (f64) | ||
437 | 84: JZ/JE Jz (f64) | ||
438 | 85: JNZ/JNE Jz (f64) | ||
439 | 86: JBE/JNA Jz (f64) | ||
440 | 87: JNBE/JA Jz (f64) | ||
441 | 88: JS Jz (f64) | ||
442 | 89: JNS Jz (f64) | ||
443 | 8a: JP/JPE Jz (f64) | ||
444 | 8b: JNP/JPO Jz (f64) | ||
445 | 8c: JL/JNGE Jz (f64) | ||
446 | 8d: JNL/JGE Jz (f64) | ||
447 | 8e: JLE/JNG Jz (f64) | ||
448 | 8f: JNLE/JG Jz (f64) | ||
449 | # 0x0f 0x90-0x9f | ||
450 | 90: SETO Eb | ||
451 | 91: SETNO Eb | ||
452 | 92: SETB/C/NAE Eb | ||
453 | 93: SETAE/NB/NC Eb | ||
454 | 94: SETE/Z Eb | ||
455 | 95: SETNE/NZ Eb | ||
456 | 96: SETBE/NA Eb | ||
457 | 97: SETA/NBE Eb | ||
458 | 98: SETS Eb | ||
459 | 99: SETNS Eb | ||
460 | 9a: SETP/PE Eb | ||
461 | 9b: SETNP/PO Eb | ||
462 | 9c: SETL/NGE Eb | ||
463 | 9d: SETNL/GE Eb | ||
464 | 9e: SETLE/NG Eb | ||
465 | 9f: SETNLE/G Eb | ||
466 | # 0x0f 0xa0-0xaf | ||
467 | a0: PUSH FS (d64) | ||
468 | a1: POP FS (d64) | ||
469 | a2: CPUID | ||
470 | a3: BT Ev,Gv | ||
471 | a4: SHLD Ev,Gv,Ib | ||
472 | a5: SHLD Ev,Gv,CL | ||
473 | a6: GrpPDLK | ||
474 | a7: GrpRNG | ||
475 | a8: PUSH GS (d64) | ||
476 | a9: POP GS (d64) | ||
477 | aa: RSM | ||
478 | ab: BTS Ev,Gv | ||
479 | ac: SHRD Ev,Gv,Ib | ||
480 | ad: SHRD Ev,Gv,CL | ||
481 | ae: Grp15 (1A),(1C) | ||
482 | af: IMUL Gv,Ev | ||
483 | # 0x0f 0xb0-0xbf | ||
484 | b0: CMPXCHG Eb,Gb | ||
485 | b1: CMPXCHG Ev,Gv | ||
486 | b2: LSS Gv,Mp | ||
487 | b3: BTR Ev,Gv | ||
488 | b4: LFS Gv,Mp | ||
489 | b5: LGS Gv,Mp | ||
490 | b6: MOVZX Gv,Eb | ||
491 | b7: MOVZX Gv,Ew | ||
492 | b8: JMPE | POPCNT Gv,Ev (F3) | ||
493 | b9: Grp10 (1A) | ||
494 | ba: Grp8 Ev,Ib (1A) | ||
495 | bb: BTC Ev,Gv | ||
496 | bc: BSF Gv,Ev | ||
497 | bd: BSR Gv,Ev | ||
498 | be: MOVSX Gv,Eb | ||
499 | bf: MOVSX Gv,Ew | ||
500 | # 0x0f 0xc0-0xcf | ||
501 | c0: XADD Eb,Gb | ||
502 | c1: XADD Ev,Gv | ||
503 | c2: cmpps Vps,Wps,Ib | cmpss Vss,Wss,Ib (F3) | cmppd Vpd,Wpd,Ib (66) | cmpsd Vsd,Wsd,Ib (F2) | ||
504 | c3: movnti Md/q,Gd/q | ||
505 | c4: pinsrw Pq,Rd/q/Mw,Ib | pinsrw Vdq,Rd/q/Mw,Ib (66) | ||
506 | c5: pextrw Gd,Nq,Ib | pextrw Gd,Udq,Ib (66) | ||
507 | c6: shufps Vps,Wps,Ib | shufpd Vpd,Wpd,Ib (66) | ||
508 | c7: Grp9 (1A) | ||
509 | c8: BSWAP RAX/EAX/R8/R8D | ||
510 | c9: BSWAP RCX/ECX/R9/R9D | ||
511 | ca: BSWAP RDX/EDX/R10/R10D | ||
512 | cb: BSWAP RBX/EBX/R11/R11D | ||
513 | cc: BSWAP RSP/ESP/R12/R12D | ||
514 | cd: BSWAP RBP/EBP/R13/R13D | ||
515 | ce: BSWAP RSI/ESI/R14/R14D | ||
516 | cf: BSWAP RDI/EDI/R15/R15D | ||
517 | # 0x0f 0xd0-0xdf | ||
518 | d0: addsubps Vps,Wps (F2) | addsubpd Vpd,Wpd (66) | ||
519 | d1: psrlw Pq,Qq | psrlw Vdq,Wdq (66) | ||
520 | d2: psrld Pq,Qq | psrld Vdq,Wdq (66) | ||
521 | d3: psrlq Pq,Qq | psrlq Vdq,Wdq (66) | ||
522 | d4: paddq Pq,Qq | paddq Vdq,Wdq (66) | ||
523 | d5: pmullw Pq,Qq | pmullw Vdq,Wdq (66) | ||
524 | d6: movq Wq,Vq (66) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) | ||
525 | d7: pmovmskb Gd,Nq | pmovmskb Gd,Udq (66) | ||
526 | d8: psubusb Pq,Qq | psubusb Vdq,Wdq (66) | ||
527 | d9: psubusw Pq,Qq | psubusw Vdq,Wdq (66) | ||
528 | da: pminub Pq,Qq | pminub Vdq,Wdq (66) | ||
529 | db: pand Pq,Qq | pand Vdq,Wdq (66) | ||
530 | dc: paddusb Pq,Qq | paddusb Vdq,Wdq (66) | ||
531 | dd: paddusw Pq,Qq | paddusw Vdq,Wdq (66) | ||
532 | de: pmaxub Pq,Qq | pmaxub Vdq,Wdq (66) | ||
533 | df: pandn Pq,Qq | pandn Vdq,Wdq (66) | ||
534 | # 0x0f 0xe0-0xef | ||
535 | e0: pavgb Pq,Qq | pavgb Vdq,Wdq (66) | ||
536 | e1: psraw Pq,Qq | psraw Vdq,Wdq (66) | ||
537 | e2: psrad Pq,Qq | psrad Vdq,Wdq (66) | ||
538 | e3: pavgw Pq,Qq | pavgw Vdq,Wdq (66) | ||
539 | e4: pmulhuw Pq,Qq | pmulhuw Vdq,Wdq (66) | ||
540 | e5: pmulhw Pq,Qq | pmulhw Vdq,Wdq (66) | ||
541 | e6: cvtpd2dq Vdq,Wpd (F2) | cvttpd2dq Vdq,Wpd (66) | cvtdq2pd Vpd,Wdq (F3) | ||
542 | e7: movntq Mq,Pq | movntdq Mdq,Vdq (66) | ||
543 | e8: psubsb Pq,Qq | psubsb Vdq,Wdq (66) | ||
544 | e9: psubsw Pq,Qq | psubsw Vdq,Wdq (66) | ||
545 | ea: pminsw Pq,Qq | pminsw Vdq,Wdq (66) | ||
546 | eb: por Pq,Qq | por Vdq,Wdq (66) | ||
547 | ec: paddsb Pq,Qq | paddsb Vdq,Wdq (66) | ||
548 | ed: paddsw Pq,Qq | paddsw Vdq,Wdq (66) | ||
549 | ee: pmaxsw Pq,Qq | pmaxsw Vdq,Wdq (66) | ||
550 | ef: pxor Pq,Qq | pxor Vdq,Wdq (66) | ||
551 | # 0x0f 0xf0-0xff | ||
552 | f0: lddqu Vdq,Mdq (F2) | ||
553 | f1: psllw Pq,Qq | psllw Vdq,Wdq (66) | ||
554 | f2: pslld Pq,Qq | pslld Vdq,Wdq (66) | ||
555 | f3: psllq Pq,Qq | psllq Vdq,Wdq (66) | ||
556 | f4: pmuludq Pq,Qq | pmuludq Vdq,Wdq (66) | ||
557 | f5: pmaddwd Pq,Qq | pmaddwd Vdq,Wdq (66) | ||
558 | f6: psadbw Pq,Qq | psadbw Vdq,Wdq (66) | ||
559 | f7: maskmovq Pq,Nq | maskmovdqu Vdq,Udq (66) | ||
560 | f8: psubb Pq,Qq | psubb Vdq,Wdq (66) | ||
561 | f9: psubw Pq,Qq | psubw Vdq,Wdq (66) | ||
562 | fa: psubd Pq,Qq | psubd Vdq,Wdq (66) | ||
563 | fb: psubq Pq,Qq | psubq Vdq,Wdq (66) | ||
564 | fc: paddb Pq,Qq | paddb Vdq,Wdq (66) | ||
565 | fd: paddw Pq,Qq | paddw Vdq,Wdq (66) | ||
566 | fe: paddd Pq,Qq | paddd Vdq,Wdq (66) | ||
567 | ff: | ||
568 | EndTable | ||
569 | |||
570 | Table: 3-byte opcode 1 | ||
571 | Referrer: 3-byte escape 1 | ||
572 | # 0x0f 0x38 0x00-0x0f | ||
573 | 00: pshufb Pq,Qq | pshufb Vdq,Wdq (66) | ||
574 | 01: phaddw Pq,Qq | phaddw Vdq,Wdq (66) | ||
575 | 02: phaddd Pq,Qq | phaddd Vdq,Wdq (66) | ||
576 | 03: phaddsw Pq,Qq | phaddsw Vdq,Wdq (66) | ||
577 | 04: pmaddubsw Pq,Qq | pmaddubsw (66)Vdq,Wdq | ||
578 | 05: phsubw Pq,Qq | phsubw Vdq,Wdq (66) | ||
579 | 06: phsubd Pq,Qq | phsubd Vdq,Wdq (66) | ||
580 | 07: phsubsw Pq,Qq | phsubsw Vdq,Wdq (66) | ||
581 | 08: psignb Pq,Qq | psignb Vdq,Wdq (66) | ||
582 | 09: psignw Pq,Qq | psignw Vdq,Wdq (66) | ||
583 | 0a: psignd Pq,Qq | psignd Vdq,Wdq (66) | ||
584 | 0b: pmulhrsw Pq,Qq | pmulhrsw Vdq,Wdq (66) | ||
585 | 0c: | ||
586 | 0d: | ||
587 | 0e: | ||
588 | 0f: | ||
589 | # 0x0f 0x38 0x10-0x1f | ||
590 | 10: pblendvb Vdq,Wdq (66) | ||
591 | 11: | ||
592 | 12: | ||
593 | 13: | ||
594 | 14: blendvps Vdq,Wdq (66) | ||
595 | 15: blendvpd Vdq,Wdq (66) | ||
596 | 16: | ||
597 | 17: ptest Vdq,Wdq (66) | ||
598 | 18: | ||
599 | 19: | ||
600 | 1a: | ||
601 | 1b: | ||
602 | 1c: pabsb Pq,Qq | pabsb Vdq,Wdq (66) | ||
603 | 1d: pabsw Pq,Qq | pabsw Vdq,Wdq (66) | ||
604 | 1e: pabsd Pq,Qq | pabsd Vdq,Wdq (66) | ||
605 | 1f: | ||
606 | # 0x0f 0x38 0x20-0x2f | ||
607 | 20: pmovsxbw Vdq,Udq/Mq (66) | ||
608 | 21: pmovsxbd Vdq,Udq/Md (66) | ||
609 | 22: pmovsxbq Vdq,Udq/Mw (66) | ||
610 | 23: pmovsxwd Vdq,Udq/Mq (66) | ||
611 | 24: pmovsxwq Vdq,Udq/Md (66) | ||
612 | 25: pmovsxdq Vdq,Udq/Mq (66) | ||
613 | 26: | ||
614 | 27: | ||
615 | 28: pmuldq Vdq,Wdq (66) | ||
616 | 29: pcmpeqq Vdq,Wdq (66) | ||
617 | 2a: movntdqa Vdq,Mdq (66) | ||
618 | 2b: packusdw Vdq,Wdq (66) | ||
619 | 2c: | ||
620 | 2d: | ||
621 | 2e: | ||
622 | 2f: | ||
623 | # 0x0f 0x38 0x30-0x3f | ||
624 | 30: pmovzxbw Vdq,Udq/Mq (66) | ||
625 | 31: pmovzxbd Vdq,Udq/Md (66) | ||
626 | 32: pmovzxbq Vdq,Udq/Mw (66) | ||
627 | 33: pmovzxwd Vdq,Udq/Mq (66) | ||
628 | 34: pmovzxwq Vdq,Udq/Md (66) | ||
629 | 35: pmovzxdq Vdq,Udq/Mq (66) | ||
630 | 36: | ||
631 | 37: pcmpgtq Vdq,Wdq (66) | ||
632 | 38: pminsb Vdq,Wdq (66) | ||
633 | 39: pminsd Vdq,Wdq (66) | ||
634 | 3a: pminuw Vdq,Wdq (66) | ||
635 | 3b: pminud Vdq,Wdq (66) | ||
636 | 3c: pmaxsb Vdq,Wdq (66) | ||
637 | 3d: pmaxsd Vdq,Wdq (66) | ||
638 | 3e: pmaxuw Vdq,Wdq (66) | ||
639 | 3f: pmaxud Vdq,Wdq (66) | ||
640 | # 0x0f 0x38 0x4f-0xff | ||
641 | 40: pmulld Vdq,Wdq (66) | ||
642 | 41: phminposuw Vdq,Wdq (66) | ||
643 | 80: INVEPT Gd/q,Mdq (66) | ||
644 | 81: INVPID Gd/q,Mdq (66) | ||
645 | f0: MOVBE Gv,Mv | CRC32 Gd,Eb (F2) | ||
646 | f1: MOVBE Mv,Gv | CRC32 Gd,Ev (F2) | ||
647 | EndTable | ||
648 | |||
649 | Table: 3-byte opcode 2 | ||
650 | Referrer: 3-byte escape 2 | ||
651 | # 0x0f 0x3a 0x00-0xff | ||
652 | 08: roundps Vdq,Wdq,Ib (66) | ||
653 | 09: roundpd Vdq,Wdq,Ib (66) | ||
654 | 0a: roundss Vss,Wss,Ib (66) | ||
655 | 0b: roundsd Vsd,Wsd,Ib (66) | ||
656 | 0c: blendps Vdq,Wdq,Ib (66) | ||
657 | 0d: blendpd Vdq,Wdq,Ib (66) | ||
658 | 0e: pblendw Vdq,Wdq,Ib (66) | ||
659 | 0f: palignr Pq,Qq,Ib | palignr Vdq,Wdq,Ib (66) | ||
660 | 14: pextrb Rd/Mb,Vdq,Ib (66) | ||
661 | 15: pextrw Rd/Mw,Vdq,Ib (66) | ||
662 | 16: pextrd/pextrq Ed/q,Vdq,Ib (66) | ||
663 | 17: extractps Ed,Vdq,Ib (66) | ||
664 | 20: pinsrb Vdq,Rd/q/Mb,Ib (66) | ||
665 | 21: insertps Vdq,Udq/Md,Ib (66) | ||
666 | 22: pinsrd/pinsrq Vdq,Ed/q,Ib (66) | ||
667 | 40: dpps Vdq,Wdq,Ib (66) | ||
668 | 41: dppd Vdq,Wdq,Ib (66) | ||
669 | 42: mpsadbw Vdq,Wdq,Ib (66) | ||
670 | 60: pcmpestrm Vdq,Wdq,Ib (66) | ||
671 | 61: pcmpestri Vdq,Wdq,Ib (66) | ||
672 | 62: pcmpistrm Vdq,Wdq,Ib (66) | ||
673 | 63: pcmpistri Vdq,Wdq,Ib (66) | ||
674 | EndTable | ||
675 | |||
676 | GrpTable: Grp1 | ||
677 | 0: ADD | ||
678 | 1: OR | ||
679 | 2: ADC | ||
680 | 3: SBB | ||
681 | 4: AND | ||
682 | 5: SUB | ||
683 | 6: XOR | ||
684 | 7: CMP | ||
685 | EndTable | ||
686 | |||
687 | GrpTable: Grp1A | ||
688 | 0: POP | ||
689 | EndTable | ||
690 | |||
691 | GrpTable: Grp2 | ||
692 | 0: ROL | ||
693 | 1: ROR | ||
694 | 2: RCL | ||
695 | 3: RCR | ||
696 | 4: SHL/SAL | ||
697 | 5: SHR | ||
698 | 6: | ||
699 | 7: SAR | ||
700 | EndTable | ||
701 | |||
702 | GrpTable: Grp3_1 | ||
703 | 0: TEST Eb,Ib | ||
704 | 1: | ||
705 | 2: NOT Eb | ||
706 | 3: NEG Eb | ||
707 | 4: MUL AL,Eb | ||
708 | 5: IMUL AL,Eb | ||
709 | 6: DIV AL,Eb | ||
710 | 7: IDIV AL,Eb | ||
711 | EndTable | ||
712 | |||
713 | GrpTable: Grp3_2 | ||
714 | 0: TEST Ev,Iz | ||
715 | 1: | ||
716 | 2: NOT Ev | ||
717 | 3: NEG Ev | ||
718 | 4: MUL rAX,Ev | ||
719 | 5: IMUL rAX,Ev | ||
720 | 6: DIV rAX,Ev | ||
721 | 7: IDIV rAX,Ev | ||
722 | EndTable | ||
723 | |||
724 | GrpTable: Grp4 | ||
725 | 0: INC Eb | ||
726 | 1: DEC Eb | ||
727 | EndTable | ||
728 | |||
729 | GrpTable: Grp5 | ||
730 | 0: INC Ev | ||
731 | 1: DEC Ev | ||
732 | 2: CALLN Ev (f64) | ||
733 | 3: CALLF Ep | ||
734 | 4: JMPN Ev (f64) | ||
735 | 5: JMPF Ep | ||
736 | 6: PUSH Ev (d64) | ||
737 | 7: | ||
738 | EndTable | ||
739 | |||
740 | GrpTable: Grp6 | ||
741 | 0: SLDT Rv/Mw | ||
742 | 1: STR Rv/Mw | ||
743 | 2: LLDT Ew | ||
744 | 3: LTR Ew | ||
745 | 4: VERR Ew | ||
746 | 5: VERW Ew | ||
747 | EndTable | ||
748 | |||
749 | GrpTable: Grp7 | ||
750 | 0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) | ||
751 | 1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001) | ||
752 | 2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | ||
753 | 3: LIDT Ms | ||
754 | 4: SMSW Mw/Rv | ||
755 | 5: | ||
756 | 6: LMSW Ew | ||
757 | 7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) | ||
758 | EndTable | ||
759 | |||
760 | GrpTable: Grp8 | ||
761 | 4: BT | ||
762 | 5: BTS | ||
763 | 6: BTR | ||
764 | 7: BTC | ||
765 | EndTable | ||
766 | |||
767 | GrpTable: Grp9 | ||
768 | 1: CMPXCHG8B/16B Mq/Mdq | ||
769 | 6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | ||
770 | 7: VMPTRST Mq | ||
771 | EndTable | ||
772 | |||
773 | GrpTable: Grp10 | ||
774 | EndTable | ||
775 | |||
776 | GrpTable: Grp11 | ||
777 | 0: MOV | ||
778 | EndTable | ||
779 | |||
780 | GrpTable: Grp12 | ||
781 | 2: psrlw Nq,Ib (11B) | psrlw Udq,Ib (66),(11B) | ||
782 | 4: psraw Nq,Ib (11B) | psraw Udq,Ib (66),(11B) | ||
783 | 6: psllw Nq,Ib (11B) | psllw Udq,Ib (66),(11B) | ||
784 | EndTable | ||
785 | |||
786 | GrpTable: Grp13 | ||
787 | 2: psrld Nq,Ib (11B) | psrld Udq,Ib (66),(11B) | ||
788 | 4: psrad Nq,Ib (11B) | psrad Udq,Ib (66),(11B) | ||
789 | 6: pslld Nq,Ib (11B) | pslld Udq,Ib (66),(11B) | ||
790 | EndTable | ||
791 | |||
792 | GrpTable: Grp14 | ||
793 | 2: psrlq Nq,Ib (11B) | psrlq Udq,Ib (66),(11B) | ||
794 | 3: psrldq Udq,Ib (66),(11B) | ||
795 | 6: psllq Nq,Ib (11B) | psllq Udq,Ib (66),(11B) | ||
796 | 7: pslldq Udq,Ib (66),(11B) | ||
797 | EndTable | ||
798 | |||
799 | GrpTable: Grp15 | ||
800 | 0: fxsave | ||
801 | 1: fxstor | ||
802 | 2: ldmxcsr | ||
803 | 3: stmxcsr | ||
804 | 4: XSAVE | ||
805 | 5: XRSTOR | lfence (11B) | ||
806 | 6: mfence (11B) | ||
807 | 7: clflush | sfence (11B) | ||
808 | EndTable | ||
809 | |||
810 | GrpTable: Grp16 | ||
811 | 0: prefetch NTA | ||
812 | 1: prefetch T0 | ||
813 | 2: prefetch T1 | ||
814 | 3: prefetch T2 | ||
815 | EndTable | ||
816 | |||
817 | # AMD's Prefetch Group | ||
818 | GrpTable: GrpP | ||
819 | 0: PREFETCH | ||
820 | 1: PREFETCHW | ||
821 | EndTable | ||
822 | |||
823 | GrpTable: GrpPDLK | ||
824 | 0: MONTMUL | ||
825 | 1: XSHA1 | ||
826 | 2: XSHA2 | ||
827 | EndTable | ||
828 | |||
829 | GrpTable: GrpRNG | ||
830 | 0: xstore-rng | ||
831 | 1: xcrypt-ecb | ||
832 | 2: xcrypt-cbc | ||
833 | 4: xcrypt-cfb | ||
834 | 5: xcrypt-ofb | ||
835 | EndTable | ||
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 | */ |
41 | static inline int kmmio_fault(struct pt_regs *regs, unsigned long addr) | 41 | static inline int __kprobes |
42 | kmmio_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 | ||
49 | static inline int notify_page_fault(struct pt_regs *regs) | 50 | static 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 | */ |
243 | static noinline int vmalloc_fault(unsigned long address) | 244 | static 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 | */ |
360 | static noinline int vmalloc_fault(unsigned long address) | 361 | static 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 | */ |
863 | static noinline int | 864 | static noinline __kprobes int |
864 | spurious_fault(unsigned long error_code, unsigned long address) | 865 | spurious_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 @@ | |||
1 | PHONY += posttest | ||
2 | quiet_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 | |||
5 | posttest: $(obj)/test_get_len vmlinux | ||
6 | $(call cmd,posttest) | ||
7 | |||
8 | hostprogs-y := test_get_len | ||
9 | |||
10 | # -I needed for generated C source and C source which in the kernel tree. | ||
11 | HOSTCFLAGS_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 | |||
9 | BEGIN { | ||
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 | |||
39 | END { | ||
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 | ||
8 | function 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 | |||
16 | BEGIN { | ||
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 | |||
82 | function semantic_error(msg) { | ||
83 | print "Semantic error at " NR ": " msg > "/dev/stderr" | ||
84 | exit 1 | ||
85 | } | ||
86 | |||
87 | function debug(msg) { | ||
88 | print "DEBUG: " msg | ||
89 | } | ||
90 | |||
91 | function 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 | |||
125 | function 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 | |||
191 | function 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. | ||
201 | function 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 | |||
313 | END { | ||
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 | |||
38 | const char *prog; | ||
39 | |||
40 | static 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 | |||
47 | static 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 | |||
55 | int 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 | } | ||