.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * 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 | 4 | * |
---|
18 | 5 | * Copyright (C) IBM Corporation, 2002, 2004, 2009 |
---|
19 | 6 | */ |
---|
.. | .. |
---|
23 | 10 | #else |
---|
24 | 11 | #include <string.h> |
---|
25 | 12 | #endif |
---|
26 | | -#include <asm/inat.h> |
---|
27 | | -#include <asm/insn.h> |
---|
| 13 | +#include <asm/inat.h> /*__ignore_sync_check__ */ |
---|
| 14 | +#include <asm/insn.h> /* __ignore_sync_check__ */ |
---|
| 15 | + |
---|
| 16 | +#include <linux/errno.h> |
---|
| 17 | +#include <linux/kconfig.h> |
---|
| 18 | + |
---|
| 19 | +#include <asm/emulate_prefix.h> /* __ignore_sync_check__ */ |
---|
28 | 20 | |
---|
29 | 21 | /* Verify next sizeof(t) bytes can be on the same instruction */ |
---|
30 | 22 | #define validate_next(t, insn, n) \ |
---|
.. | .. |
---|
71 | 63 | insn->addr_bytes = 4; |
---|
72 | 64 | } |
---|
73 | 65 | |
---|
| 66 | +static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX }; |
---|
| 67 | +static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX }; |
---|
| 68 | + |
---|
| 69 | +static int __insn_get_emulate_prefix(struct insn *insn, |
---|
| 70 | + const insn_byte_t *prefix, size_t len) |
---|
| 71 | +{ |
---|
| 72 | + size_t i; |
---|
| 73 | + |
---|
| 74 | + for (i = 0; i < len; i++) { |
---|
| 75 | + if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i]) |
---|
| 76 | + goto err_out; |
---|
| 77 | + } |
---|
| 78 | + |
---|
| 79 | + insn->emulate_prefix_size = len; |
---|
| 80 | + insn->next_byte += len; |
---|
| 81 | + |
---|
| 82 | + return 1; |
---|
| 83 | + |
---|
| 84 | +err_out: |
---|
| 85 | + return 0; |
---|
| 86 | +} |
---|
| 87 | + |
---|
| 88 | +static void insn_get_emulate_prefix(struct insn *insn) |
---|
| 89 | +{ |
---|
| 90 | + if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix))) |
---|
| 91 | + return; |
---|
| 92 | + |
---|
| 93 | + __insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix)); |
---|
| 94 | +} |
---|
| 95 | + |
---|
74 | 96 | /** |
---|
75 | 97 | * insn_get_prefixes - scan x86 instruction prefix bytes |
---|
76 | 98 | * @insn: &struct insn containing instruction |
---|
.. | .. |
---|
78 | 100 | * Populates the @insn->prefixes bitmap, and updates @insn->next_byte |
---|
79 | 101 | * to point to the (first) opcode. No effect if @insn->prefixes.got |
---|
80 | 102 | * is already set. |
---|
| 103 | + * |
---|
| 104 | + * * Returns: |
---|
| 105 | + * 0: on success |
---|
| 106 | + * < 0: on error |
---|
81 | 107 | */ |
---|
82 | | -void insn_get_prefixes(struct insn *insn) |
---|
| 108 | +int insn_get_prefixes(struct insn *insn) |
---|
83 | 109 | { |
---|
84 | 110 | struct insn_field *prefixes = &insn->prefixes; |
---|
85 | 111 | insn_attr_t attr; |
---|
.. | .. |
---|
87 | 113 | int i, nb; |
---|
88 | 114 | |
---|
89 | 115 | if (prefixes->got) |
---|
90 | | - return; |
---|
| 116 | + return 0; |
---|
| 117 | + |
---|
| 118 | + insn_get_emulate_prefix(insn); |
---|
91 | 119 | |
---|
92 | 120 | nb = 0; |
---|
93 | 121 | lb = 0; |
---|
.. | .. |
---|
196 | 224 | |
---|
197 | 225 | prefixes->got = 1; |
---|
198 | 226 | |
---|
| 227 | + return 0; |
---|
| 228 | + |
---|
199 | 229 | err_out: |
---|
200 | | - return; |
---|
| 230 | + return -ENODATA; |
---|
201 | 231 | } |
---|
202 | 232 | |
---|
203 | 233 | /** |
---|
.. | .. |
---|
209 | 239 | * If necessary, first collects any preceding (prefix) bytes. |
---|
210 | 240 | * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got |
---|
211 | 241 | * is already 1. |
---|
| 242 | + * |
---|
| 243 | + * Returns: |
---|
| 244 | + * 0: on success |
---|
| 245 | + * < 0: on error |
---|
212 | 246 | */ |
---|
213 | | -void insn_get_opcode(struct insn *insn) |
---|
| 247 | +int insn_get_opcode(struct insn *insn) |
---|
214 | 248 | { |
---|
215 | 249 | struct insn_field *opcode = &insn->opcode; |
---|
| 250 | + int pfx_id, ret; |
---|
216 | 251 | insn_byte_t op; |
---|
217 | | - int pfx_id; |
---|
| 252 | + |
---|
218 | 253 | if (opcode->got) |
---|
219 | | - return; |
---|
220 | | - if (!insn->prefixes.got) |
---|
221 | | - insn_get_prefixes(insn); |
---|
| 254 | + return 0; |
---|
| 255 | + |
---|
| 256 | + if (!insn->prefixes.got) { |
---|
| 257 | + ret = insn_get_prefixes(insn); |
---|
| 258 | + if (ret) |
---|
| 259 | + return ret; |
---|
| 260 | + } |
---|
222 | 261 | |
---|
223 | 262 | /* Get first opcode */ |
---|
224 | 263 | op = get_next(insn_byte_t, insn); |
---|
.. | .. |
---|
233 | 272 | insn->attr = inat_get_avx_attribute(op, m, p); |
---|
234 | 273 | if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || |
---|
235 | 274 | (!inat_accept_vex(insn->attr) && |
---|
236 | | - !inat_is_group(insn->attr))) |
---|
237 | | - insn->attr = 0; /* This instruction is bad */ |
---|
238 | | - goto end; /* VEX has only 1 byte for opcode */ |
---|
| 275 | + !inat_is_group(insn->attr))) { |
---|
| 276 | + /* This instruction is bad */ |
---|
| 277 | + insn->attr = 0; |
---|
| 278 | + return -EINVAL; |
---|
| 279 | + } |
---|
| 280 | + /* VEX has only 1 byte for opcode */ |
---|
| 281 | + goto end; |
---|
239 | 282 | } |
---|
240 | 283 | |
---|
241 | 284 | insn->attr = inat_get_opcode_attribute(op); |
---|
.. | .. |
---|
246 | 289 | pfx_id = insn_last_prefix_id(insn); |
---|
247 | 290 | insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); |
---|
248 | 291 | } |
---|
249 | | - if (inat_must_vex(insn->attr)) |
---|
250 | | - insn->attr = 0; /* This instruction is bad */ |
---|
| 292 | + |
---|
| 293 | + if (inat_must_vex(insn->attr)) { |
---|
| 294 | + /* This instruction is bad */ |
---|
| 295 | + insn->attr = 0; |
---|
| 296 | + return -EINVAL; |
---|
| 297 | + } |
---|
251 | 298 | end: |
---|
252 | 299 | opcode->got = 1; |
---|
| 300 | + return 0; |
---|
253 | 301 | |
---|
254 | 302 | err_out: |
---|
255 | | - return; |
---|
| 303 | + return -ENODATA; |
---|
256 | 304 | } |
---|
257 | 305 | |
---|
258 | 306 | /** |
---|
.. | .. |
---|
262 | 310 | * Populates @insn->modrm and updates @insn->next_byte to point past the |
---|
263 | 311 | * ModRM byte, if any. If necessary, first collects the preceding bytes |
---|
264 | 312 | * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. |
---|
| 313 | + * |
---|
| 314 | + * Returns: |
---|
| 315 | + * 0: on success |
---|
| 316 | + * < 0: on error |
---|
265 | 317 | */ |
---|
266 | | -void insn_get_modrm(struct insn *insn) |
---|
| 318 | +int insn_get_modrm(struct insn *insn) |
---|
267 | 319 | { |
---|
268 | 320 | struct insn_field *modrm = &insn->modrm; |
---|
269 | 321 | insn_byte_t pfx_id, mod; |
---|
| 322 | + int ret; |
---|
| 323 | + |
---|
270 | 324 | if (modrm->got) |
---|
271 | | - return; |
---|
272 | | - if (!insn->opcode.got) |
---|
273 | | - insn_get_opcode(insn); |
---|
| 325 | + return 0; |
---|
| 326 | + |
---|
| 327 | + if (!insn->opcode.got) { |
---|
| 328 | + ret = insn_get_opcode(insn); |
---|
| 329 | + if (ret) |
---|
| 330 | + return ret; |
---|
| 331 | + } |
---|
274 | 332 | |
---|
275 | 333 | if (inat_has_modrm(insn->attr)) { |
---|
276 | 334 | mod = get_next(insn_byte_t, insn); |
---|
.. | .. |
---|
280 | 338 | pfx_id = insn_last_prefix_id(insn); |
---|
281 | 339 | insn->attr = inat_get_group_attribute(mod, pfx_id, |
---|
282 | 340 | insn->attr); |
---|
283 | | - if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) |
---|
284 | | - insn->attr = 0; /* This is bad */ |
---|
| 341 | + if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) { |
---|
| 342 | + /* Bad insn */ |
---|
| 343 | + insn->attr = 0; |
---|
| 344 | + return -EINVAL; |
---|
| 345 | + } |
---|
285 | 346 | } |
---|
286 | 347 | } |
---|
287 | 348 | |
---|
288 | 349 | if (insn->x86_64 && inat_is_force64(insn->attr)) |
---|
289 | 350 | insn->opnd_bytes = 8; |
---|
| 351 | + |
---|
290 | 352 | modrm->got = 1; |
---|
| 353 | + return 0; |
---|
291 | 354 | |
---|
292 | 355 | err_out: |
---|
293 | | - return; |
---|
| 356 | + return -ENODATA; |
---|
294 | 357 | } |
---|
295 | 358 | |
---|
296 | 359 | |
---|
.. | .. |
---|
304 | 367 | int insn_rip_relative(struct insn *insn) |
---|
305 | 368 | { |
---|
306 | 369 | struct insn_field *modrm = &insn->modrm; |
---|
| 370 | + int ret; |
---|
307 | 371 | |
---|
308 | 372 | if (!insn->x86_64) |
---|
309 | 373 | return 0; |
---|
310 | | - if (!modrm->got) |
---|
311 | | - insn_get_modrm(insn); |
---|
| 374 | + |
---|
| 375 | + if (!modrm->got) { |
---|
| 376 | + ret = insn_get_modrm(insn); |
---|
| 377 | + if (ret) |
---|
| 378 | + return 0; |
---|
| 379 | + } |
---|
312 | 380 | /* |
---|
313 | 381 | * For rip-relative instructions, the mod field (top 2 bits) |
---|
314 | 382 | * is zero and the r/m field (bottom 3 bits) is 0x5. |
---|
.. | .. |
---|
322 | 390 | * |
---|
323 | 391 | * If necessary, first collects the instruction up to and including the |
---|
324 | 392 | * ModRM byte. |
---|
| 393 | + * |
---|
| 394 | + * Returns: |
---|
| 395 | + * 0: if decoding succeeded |
---|
| 396 | + * < 0: otherwise. |
---|
325 | 397 | */ |
---|
326 | | -void insn_get_sib(struct insn *insn) |
---|
| 398 | +int insn_get_sib(struct insn *insn) |
---|
327 | 399 | { |
---|
328 | 400 | insn_byte_t modrm; |
---|
| 401 | + int ret; |
---|
329 | 402 | |
---|
330 | 403 | if (insn->sib.got) |
---|
331 | | - return; |
---|
332 | | - if (!insn->modrm.got) |
---|
333 | | - insn_get_modrm(insn); |
---|
| 404 | + return 0; |
---|
| 405 | + |
---|
| 406 | + if (!insn->modrm.got) { |
---|
| 407 | + ret = insn_get_modrm(insn); |
---|
| 408 | + if (ret) |
---|
| 409 | + return ret; |
---|
| 410 | + } |
---|
| 411 | + |
---|
334 | 412 | if (insn->modrm.nbytes) { |
---|
335 | 413 | modrm = (insn_byte_t)insn->modrm.value; |
---|
336 | 414 | if (insn->addr_bytes != 2 && |
---|
.. | .. |
---|
341 | 419 | } |
---|
342 | 420 | insn->sib.got = 1; |
---|
343 | 421 | |
---|
| 422 | + return 0; |
---|
| 423 | + |
---|
344 | 424 | err_out: |
---|
345 | | - return; |
---|
| 425 | + return -ENODATA; |
---|
346 | 426 | } |
---|
347 | 427 | |
---|
348 | 428 | |
---|
.. | .. |
---|
353 | 433 | * If necessary, first collects the instruction up to and including the |
---|
354 | 434 | * SIB byte. |
---|
355 | 435 | * Displacement value is sign-expanded. |
---|
| 436 | + * |
---|
| 437 | + * * Returns: |
---|
| 438 | + * 0: if decoding succeeded |
---|
| 439 | + * < 0: otherwise. |
---|
356 | 440 | */ |
---|
357 | | -void insn_get_displacement(struct insn *insn) |
---|
| 441 | +int insn_get_displacement(struct insn *insn) |
---|
358 | 442 | { |
---|
359 | 443 | insn_byte_t mod, rm, base; |
---|
| 444 | + int ret; |
---|
360 | 445 | |
---|
361 | 446 | if (insn->displacement.got) |
---|
362 | | - return; |
---|
363 | | - if (!insn->sib.got) |
---|
364 | | - insn_get_sib(insn); |
---|
| 447 | + return 0; |
---|
| 448 | + |
---|
| 449 | + if (!insn->sib.got) { |
---|
| 450 | + ret = insn_get_sib(insn); |
---|
| 451 | + if (ret) |
---|
| 452 | + return ret; |
---|
| 453 | + } |
---|
| 454 | + |
---|
365 | 455 | if (insn->modrm.nbytes) { |
---|
366 | 456 | /* |
---|
367 | 457 | * Interpreting the modrm byte: |
---|
.. | .. |
---|
404 | 494 | } |
---|
405 | 495 | out: |
---|
406 | 496 | insn->displacement.got = 1; |
---|
| 497 | + return 0; |
---|
407 | 498 | |
---|
408 | 499 | err_out: |
---|
409 | | - return; |
---|
| 500 | + return -ENODATA; |
---|
410 | 501 | } |
---|
411 | 502 | |
---|
412 | 503 | /* Decode moffset16/32/64. Return 0 if failed */ |
---|
.. | .. |
---|
517 | 608 | } |
---|
518 | 609 | |
---|
519 | 610 | /** |
---|
520 | | - * insn_get_immediate() - Get the immediates of instruction |
---|
| 611 | + * insn_get_immediate() - Get the immediate in an instruction |
---|
521 | 612 | * @insn: &struct insn containing instruction |
---|
522 | 613 | * |
---|
523 | 614 | * If necessary, first collects the instruction up to and including the |
---|
524 | 615 | * displacement bytes. |
---|
525 | 616 | * Basically, most of immediates are sign-expanded. Unsigned-value can be |
---|
526 | | - * get by bit masking with ((1 << (nbytes * 8)) - 1) |
---|
| 617 | + * computed by bit masking with ((1 << (nbytes * 8)) - 1) |
---|
| 618 | + * |
---|
| 619 | + * Returns: |
---|
| 620 | + * 0: on success |
---|
| 621 | + * < 0: on error |
---|
527 | 622 | */ |
---|
528 | | -void insn_get_immediate(struct insn *insn) |
---|
| 623 | +int insn_get_immediate(struct insn *insn) |
---|
529 | 624 | { |
---|
| 625 | + int ret; |
---|
| 626 | + |
---|
530 | 627 | if (insn->immediate.got) |
---|
531 | | - return; |
---|
532 | | - if (!insn->displacement.got) |
---|
533 | | - insn_get_displacement(insn); |
---|
| 628 | + return 0; |
---|
| 629 | + |
---|
| 630 | + if (!insn->displacement.got) { |
---|
| 631 | + ret = insn_get_displacement(insn); |
---|
| 632 | + if (ret) |
---|
| 633 | + return ret; |
---|
| 634 | + } |
---|
534 | 635 | |
---|
535 | 636 | if (inat_has_moffset(insn->attr)) { |
---|
536 | 637 | if (!__get_moffset(insn)) |
---|
.. | .. |
---|
583 | 684 | } |
---|
584 | 685 | done: |
---|
585 | 686 | insn->immediate.got = 1; |
---|
| 687 | + return 0; |
---|
586 | 688 | |
---|
587 | 689 | err_out: |
---|
588 | | - return; |
---|
| 690 | + return -ENODATA; |
---|
589 | 691 | } |
---|
590 | 692 | |
---|
591 | 693 | /** |
---|
.. | .. |
---|
594 | 696 | * |
---|
595 | 697 | * If necessary, first collects the instruction up to and including the |
---|
596 | 698 | * immediates bytes. |
---|
597 | | - */ |
---|
598 | | -void insn_get_length(struct insn *insn) |
---|
| 699 | + * |
---|
| 700 | + * Returns: |
---|
| 701 | + * - 0 on success |
---|
| 702 | + * - < 0 on error |
---|
| 703 | +*/ |
---|
| 704 | +int insn_get_length(struct insn *insn) |
---|
599 | 705 | { |
---|
| 706 | + int ret; |
---|
| 707 | + |
---|
600 | 708 | if (insn->length) |
---|
601 | | - return; |
---|
602 | | - if (!insn->immediate.got) |
---|
603 | | - insn_get_immediate(insn); |
---|
| 709 | + return 0; |
---|
| 710 | + |
---|
| 711 | + if (!insn->immediate.got) { |
---|
| 712 | + ret = insn_get_immediate(insn); |
---|
| 713 | + if (ret) |
---|
| 714 | + return ret; |
---|
| 715 | + } |
---|
| 716 | + |
---|
604 | 717 | insn->length = (unsigned char)((unsigned long)insn->next_byte |
---|
605 | 718 | - (unsigned long)insn->kaddr); |
---|
| 719 | + |
---|
| 720 | + return 0; |
---|
| 721 | +} |
---|
| 722 | + |
---|
| 723 | +/** |
---|
| 724 | + * insn_decode() - Decode an x86 instruction |
---|
| 725 | + * @insn: &struct insn to be initialized |
---|
| 726 | + * @kaddr: address (in kernel memory) of instruction (or copy thereof) |
---|
| 727 | + * @buf_len: length of the insn buffer at @kaddr |
---|
| 728 | + * @m: insn mode, see enum insn_mode |
---|
| 729 | + * |
---|
| 730 | + * Returns: |
---|
| 731 | + * 0: if decoding succeeded |
---|
| 732 | + * < 0: otherwise. |
---|
| 733 | + */ |
---|
| 734 | +int insn_decode(struct insn *insn, const void *kaddr, int buf_len, enum insn_mode m) |
---|
| 735 | +{ |
---|
| 736 | + int ret; |
---|
| 737 | + |
---|
| 738 | +/* #define INSN_MODE_KERN -1 __ignore_sync_check__ mode is only valid in the kernel */ |
---|
| 739 | + |
---|
| 740 | + if (m == INSN_MODE_KERN) |
---|
| 741 | + insn_init(insn, kaddr, buf_len, IS_ENABLED(CONFIG_X86_64)); |
---|
| 742 | + else |
---|
| 743 | + insn_init(insn, kaddr, buf_len, m == INSN_MODE_64); |
---|
| 744 | + |
---|
| 745 | + ret = insn_get_length(insn); |
---|
| 746 | + if (ret) |
---|
| 747 | + return ret; |
---|
| 748 | + |
---|
| 749 | + if (insn_complete(insn)) |
---|
| 750 | + return 0; |
---|
| 751 | + |
---|
| 752 | + return -EINVAL; |
---|
606 | 753 | } |
---|