LCOV - code coverage report
Current view: top level - arch/x86/lib - insn.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 130 315 41.3 %
Date: 2022-04-01 14:17:54 Functions: 10 14 71.4 %
Branches: 58 263 22.1 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * x86 instruction analysis
       4                 :            :  *
       5                 :            :  * Copyright (C) IBM Corporation, 2002, 2004, 2009
       6                 :            :  */
       7                 :            : 
       8                 :            : #ifdef __KERNEL__
       9                 :            : #include <linux/string.h>
      10                 :            : #else
      11                 :            : #include <string.h>
      12                 :            : #endif
      13                 :            : #include <asm/inat.h>
      14                 :            : #include <asm/insn.h>
      15                 :            : 
      16                 :            : #include <asm/emulate_prefix.h>
      17                 :            : 
      18                 :            : /* Verify next sizeof(t) bytes can be on the same instruction */
      19                 :            : #define validate_next(t, insn, n)       \
      20                 :            :         ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
      21                 :            : 
      22                 :            : #define __get_next(t, insn)     \
      23                 :            :         ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; })
      24                 :            : 
      25                 :            : #define __peek_nbyte_next(t, insn, n)   \
      26                 :            :         ({ t r = *(t*)((insn)->next_byte + n); r; })
      27                 :            : 
      28                 :            : #define get_next(t, insn)       \
      29                 :            :         ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); })
      30                 :            : 
      31                 :            : #define peek_nbyte_next(t, insn, n)     \
      32                 :            :         ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); })
      33                 :            : 
      34                 :            : #define peek_next(t, insn)      peek_nbyte_next(t, insn, 0)
      35                 :            : 
      36                 :            : /**
      37                 :            :  * insn_init() - initialize struct insn
      38                 :            :  * @insn:       &struct insn to be initialized
      39                 :            :  * @kaddr:      address (in kernel memory) of instruction (or copy thereof)
      40                 :            :  * @x86_64:     !0 for 64-bit kernel or 64-bit app
      41                 :            :  */
      42                 :        605 : void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
      43                 :            : {
      44                 :            :         /*
      45                 :            :          * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid
      46                 :            :          * even if the input buffer is long enough to hold them.
      47                 :            :          */
      48                 :        605 :         if (buf_len > MAX_INSN_SIZE)
      49                 :            :                 buf_len = MAX_INSN_SIZE;
      50                 :            : 
      51                 :        605 :         memset(insn, 0, sizeof(*insn));
      52                 :        605 :         insn->kaddr = kaddr;
      53                 :        605 :         insn->end_kaddr = kaddr + buf_len;
      54                 :        605 :         insn->next_byte = kaddr;
      55                 :        605 :         insn->x86_64 = x86_64 ? 1 : 0;
      56                 :        605 :         insn->opnd_bytes = 4;
      57         [ +  - ]:        605 :         if (x86_64)
      58                 :        605 :                 insn->addr_bytes = 8;
      59                 :            :         else
      60                 :          0 :                 insn->addr_bytes = 4;
      61                 :        605 : }
      62                 :            : 
      63                 :            : static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX };
      64                 :            : static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX };
      65                 :            : 
      66                 :        605 : static int __insn_get_emulate_prefix(struct insn *insn,
      67                 :            :                                      const insn_byte_t *prefix, size_t len)
      68                 :            : {
      69                 :        605 :         size_t i;
      70                 :            : 
      71   [ +  -  +  - ]:       1210 :         for (i = 0; i < len; i++) {
      72   [ -  +  +  -  :       1210 :                 if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i])
             -  +  +  - ]
      73                 :       1210 :                         goto err_out;
      74                 :            :         }
      75                 :            : 
      76                 :          0 :         insn->emulate_prefix_size = len;
      77                 :          0 :         insn->next_byte += len;
      78                 :            : 
      79                 :          0 :         return 1;
      80                 :            : 
      81                 :            : err_out:
      82                 :            :         return 0;
      83                 :            : }
      84                 :            : 
      85                 :        605 : static void insn_get_emulate_prefix(struct insn *insn)
      86                 :            : {
      87                 :        605 :         if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix)))
      88                 :          0 :                 return;
      89                 :            : 
      90                 :            :         __insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix));
      91                 :            : }
      92                 :            : 
      93                 :            : /**
      94                 :            :  * insn_get_prefixes - scan x86 instruction prefix bytes
      95                 :            :  * @insn:       &struct insn containing instruction
      96                 :            :  *
      97                 :            :  * Populates the @insn->prefixes bitmap, and updates @insn->next_byte
      98                 :            :  * to point to the (first) opcode.  No effect if @insn->prefixes.got
      99                 :            :  * is already set.
     100                 :            :  */
     101                 :        605 : void insn_get_prefixes(struct insn *insn)
     102                 :            : {
     103                 :        605 :         struct insn_field *prefixes = &insn->prefixes;
     104                 :        605 :         insn_attr_t attr;
     105                 :        605 :         insn_byte_t b, lb;
     106                 :        605 :         int i, nb;
     107                 :            : 
     108         [ +  - ]:        605 :         if (prefixes->got)
     109                 :            :                 return;
     110                 :            : 
     111                 :        605 :         insn_get_emulate_prefix(insn);
     112                 :            : 
     113                 :        605 :         nb = 0;
     114                 :        605 :         lb = 0;
     115         [ -  + ]:        605 :         b = peek_next(insn_byte_t, insn);
     116                 :        605 :         attr = inat_get_opcode_attribute(b);
     117         [ +  + ]:       1221 :         while (inat_is_legacy_prefix(attr)) {
     118                 :            :                 /* Skip if same prefix */
     119         [ +  + ]:        616 :                 for (i = 0; i < nb; i++)
     120         [ +  - ]:        462 :                         if (prefixes->bytes[i] == b)
     121                 :        462 :                                 goto found;
     122         [ +  - ]:        154 :                 if (nb == 4)
     123                 :            :                         /* Invalid instruction */
     124                 :            :                         break;
     125                 :        154 :                 prefixes->bytes[nb++] = b;
     126         [ -  + ]:        154 :                 if (inat_is_address_size_prefix(attr)) {
     127                 :            :                         /* address size switches 2/4 or 4/8 */
     128         [ #  # ]:          0 :                         if (insn->x86_64)
     129                 :          0 :                                 insn->addr_bytes ^= 12;
     130                 :            :                         else
     131                 :          0 :                                 insn->addr_bytes ^= 6;
     132         [ -  + ]:        154 :                 } else if (inat_is_operand_size_prefix(attr)) {
     133                 :            :                         /* oprand size switches 2/4 */
     134                 :        154 :                         insn->opnd_bytes ^= 6;
     135                 :            :                 }
     136                 :          0 : found:
     137                 :        616 :                 prefixes->nbytes++;
     138                 :        616 :                 insn->next_byte++;
     139                 :        616 :                 lb = b;
     140         [ -  + ]:        616 :                 b = peek_next(insn_byte_t, insn);
     141                 :        616 :                 attr = inat_get_opcode_attribute(b);
     142                 :            :         }
     143                 :            :         /* Set the last prefix */
     144   [ +  +  +  - ]:        605 :         if (lb && lb != insn->prefixes.bytes[3]) {
     145         [ -  + ]:        154 :                 if (unlikely(insn->prefixes.bytes[3])) {
     146                 :            :                         /* Swap the last prefix */
     147                 :            :                         b = insn->prefixes.bytes[3];
     148         [ #  # ]:          0 :                         for (i = 0; i < nb; i++)
     149         [ #  # ]:          0 :                                 if (prefixes->bytes[i] == lb)
     150                 :          0 :                                         prefixes->bytes[i] = b;
     151                 :            :                 }
     152                 :        154 :                 insn->prefixes.bytes[3] = lb;
     153                 :            :         }
     154                 :            : 
     155                 :            :         /* Decode REX prefix */
     156         [ +  - ]:        605 :         if (insn->x86_64) {
     157         [ -  + ]:        605 :                 b = peek_next(insn_byte_t, insn);
     158                 :        605 :                 attr = inat_get_opcode_attribute(b);
     159         [ -  + ]:        605 :                 if (inat_is_rex_prefix(attr)) {
     160                 :          0 :                         insn->rex_prefix.value = b;
     161                 :          0 :                         insn->rex_prefix.nbytes = 1;
     162                 :          0 :                         insn->next_byte++;
     163         [ #  # ]:          0 :                         if (X86_REX_W(b))
     164                 :            :                                 /* REX.W overrides opnd_size */
     165                 :          0 :                                 insn->opnd_bytes = 8;
     166                 :            :                 }
     167                 :            :         }
     168                 :        605 :         insn->rex_prefix.got = 1;
     169                 :            : 
     170                 :            :         /* Decode VEX prefix */
     171         [ -  + ]:        605 :         b = peek_next(insn_byte_t, insn);
     172                 :        605 :         attr = inat_get_opcode_attribute(b);
     173         [ +  - ]:        605 :         if (inat_is_vex_prefix(attr)) {
     174         [ #  # ]:          0 :                 insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1);
     175         [ #  # ]:          0 :                 if (!insn->x86_64) {
     176                 :            :                         /*
     177                 :            :                          * In 32-bits mode, if the [7:6] bits (mod bits of
     178                 :            :                          * ModRM) on the second byte are not 11b, it is
     179                 :            :                          * LDS or LES or BOUND.
     180                 :            :                          */
     181         [ #  # ]:          0 :                         if (X86_MODRM_MOD(b2) != 3)
     182                 :          0 :                                 goto vex_end;
     183                 :            :                 }
     184                 :          0 :                 insn->vex_prefix.bytes[0] = b;
     185                 :          0 :                 insn->vex_prefix.bytes[1] = b2;
     186         [ #  # ]:          0 :                 if (inat_is_evex_prefix(attr)) {
     187         [ #  # ]:          0 :                         b2 = peek_nbyte_next(insn_byte_t, insn, 2);
     188                 :          0 :                         insn->vex_prefix.bytes[2] = b2;
     189         [ #  # ]:          0 :                         b2 = peek_nbyte_next(insn_byte_t, insn, 3);
     190                 :          0 :                         insn->vex_prefix.bytes[3] = b2;
     191                 :          0 :                         insn->vex_prefix.nbytes = 4;
     192                 :          0 :                         insn->next_byte += 4;
     193   [ #  #  #  # ]:          0 :                         if (insn->x86_64 && X86_VEX_W(b2))
     194                 :            :                                 /* VEX.W overrides opnd_size */
     195                 :          0 :                                 insn->opnd_bytes = 8;
     196         [ #  # ]:          0 :                 } else if (inat_is_vex3_prefix(attr)) {
     197         [ #  # ]:          0 :                         b2 = peek_nbyte_next(insn_byte_t, insn, 2);
     198                 :          0 :                         insn->vex_prefix.bytes[2] = b2;
     199                 :          0 :                         insn->vex_prefix.nbytes = 3;
     200                 :          0 :                         insn->next_byte += 3;
     201   [ #  #  #  # ]:          0 :                         if (insn->x86_64 && X86_VEX_W(b2))
     202                 :            :                                 /* VEX.W overrides opnd_size */
     203                 :          0 :                                 insn->opnd_bytes = 8;
     204                 :            :                 } else {
     205                 :            :                         /*
     206                 :            :                          * For VEX2, fake VEX3-like byte#2.
     207                 :            :                          * Makes it easier to decode vex.W, vex.vvvv,
     208                 :            :                          * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0.
     209                 :            :                          */
     210                 :          0 :                         insn->vex_prefix.bytes[2] = b2 & 0x7f;
     211                 :          0 :                         insn->vex_prefix.nbytes = 2;
     212                 :          0 :                         insn->next_byte += 2;
     213                 :            :                 }
     214                 :            :         }
     215                 :        605 : vex_end:
     216                 :        605 :         insn->vex_prefix.got = 1;
     217                 :            : 
     218                 :        605 :         prefixes->got = 1;
     219                 :            : 
     220                 :        605 : err_out:
     221                 :            :         return;
     222                 :            : }
     223                 :            : 
     224                 :            : /**
     225                 :            :  * insn_get_opcode - collect opcode(s)
     226                 :            :  * @insn:       &struct insn containing instruction
     227                 :            :  *
     228                 :            :  * Populates @insn->opcode, updates @insn->next_byte to point past the
     229                 :            :  * opcode byte(s), and set @insn->attr (except for groups).
     230                 :            :  * If necessary, first collects any preceding (prefix) bytes.
     231                 :            :  * Sets @insn->opcode.value = opcode1.  No effect if @insn->opcode.got
     232                 :            :  * is already 1.
     233                 :            :  */
     234                 :        605 : void insn_get_opcode(struct insn *insn)
     235                 :            : {
     236                 :        605 :         struct insn_field *opcode = &insn->opcode;
     237                 :        605 :         insn_byte_t op;
     238                 :        605 :         int pfx_id;
     239         [ +  - ]:        605 :         if (opcode->got)
     240                 :            :                 return;
     241         [ +  - ]:        605 :         if (!insn->prefixes.got)
     242                 :        605 :                 insn_get_prefixes(insn);
     243                 :            : 
     244                 :            :         /* Get first opcode */
     245         [ -  + ]:        605 :         op = get_next(insn_byte_t, insn);
     246                 :        605 :         opcode->bytes[0] = op;
     247                 :        605 :         opcode->nbytes = 1;
     248                 :            : 
     249                 :            :         /* Check if there is VEX prefix or not */
     250   [ -  +  -  + ]:        605 :         if (insn_is_avx(insn)) {
     251                 :          0 :                 insn_byte_t m, p;
     252         [ #  # ]:          0 :                 m = insn_vex_m_bits(insn);
     253         [ #  # ]:          0 :                 p = insn_vex_p_bits(insn);
     254                 :          0 :                 insn->attr = inat_get_avx_attribute(op, m, p);
     255   [ #  #  #  #  :          0 :                 if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) ||
                   #  # ]
     256   [ #  #  #  # ]:          0 :                     (!inat_accept_vex(insn->attr) &&
     257                 :            :                      !inat_is_group(insn->attr)))
     258                 :          0 :                         insn->attr = 0;      /* This instruction is bad */
     259                 :          0 :                 goto end;       /* VEX has only 1 byte for opcode */
     260                 :            :         }
     261                 :            : 
     262                 :        605 :         insn->attr = inat_get_opcode_attribute(op);
     263         [ -  + ]:        605 :         while (inat_is_escape(insn->attr)) {
     264                 :            :                 /* Get escaped opcode */
     265         [ #  # ]:          0 :                 op = get_next(insn_byte_t, insn);
     266                 :          0 :                 opcode->bytes[opcode->nbytes++] = op;
     267                 :          0 :                 pfx_id = insn_last_prefix_id(insn);
     268                 :          0 :                 insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr);
     269                 :            :         }
     270         [ +  - ]:        605 :         if (inat_must_vex(insn->attr))
     271                 :          0 :                 insn->attr = 0;      /* This instruction is bad */
     272                 :        605 : end:
     273                 :        605 :         opcode->got = 1;
     274                 :            : 
     275                 :        605 : err_out:
     276                 :            :         return;
     277                 :            : }
     278                 :            : 
     279                 :            : /**
     280                 :            :  * insn_get_modrm - collect ModRM byte, if any
     281                 :            :  * @insn:       &struct insn containing instruction
     282                 :            :  *
     283                 :            :  * Populates @insn->modrm and updates @insn->next_byte to point past the
     284                 :            :  * ModRM byte, if any.  If necessary, first collects the preceding bytes
     285                 :            :  * (prefixes and opcode(s)).  No effect if @insn->modrm.got is already 1.
     286                 :            :  */
     287                 :        605 : void insn_get_modrm(struct insn *insn)
     288                 :            : {
     289                 :        605 :         struct insn_field *modrm = &insn->modrm;
     290                 :        605 :         insn_byte_t pfx_id, mod;
     291         [ +  - ]:        605 :         if (modrm->got)
     292                 :            :                 return;
     293         [ +  - ]:        605 :         if (!insn->opcode.got)
     294                 :        605 :                 insn_get_opcode(insn);
     295                 :            : 
     296         [ -  + ]:        605 :         if (inat_has_modrm(insn->attr)) {
     297         [ #  # ]:          0 :                 mod = get_next(insn_byte_t, insn);
     298                 :          0 :                 modrm->value = mod;
     299                 :          0 :                 modrm->nbytes = 1;
     300         [ #  # ]:          0 :                 if (inat_is_group(insn->attr)) {
     301                 :          0 :                         pfx_id = insn_last_prefix_id(insn);
     302                 :          0 :                         insn->attr = inat_get_group_attribute(mod, pfx_id,
     303                 :            :                                                               insn->attr);
     304   [ #  #  #  #  :          0 :                         if (insn_is_avx(insn) && !inat_accept_vex(insn->attr))
                   #  # ]
     305                 :          0 :                                 insn->attr = 0;      /* This is bad */
     306                 :            :                 }
     307                 :            :         }
     308                 :            : 
     309   [ +  -  +  + ]:        605 :         if (insn->x86_64 && inat_is_force64(insn->attr))
     310                 :        451 :                 insn->opnd_bytes = 8;
     311                 :        605 :         modrm->got = 1;
     312                 :            : 
     313                 :        605 : err_out:
     314                 :            :         return;
     315                 :            : }
     316                 :            : 
     317                 :            : 
     318                 :            : /**
     319                 :            :  * insn_rip_relative() - Does instruction use RIP-relative addressing mode?
     320                 :            :  * @insn:       &struct insn containing instruction
     321                 :            :  *
     322                 :            :  * If necessary, first collects the instruction up to and including the
     323                 :            :  * ModRM byte.  No effect if @insn->x86_64 is 0.
     324                 :            :  */
     325                 :          0 : int insn_rip_relative(struct insn *insn)
     326                 :            : {
     327                 :          0 :         struct insn_field *modrm = &insn->modrm;
     328                 :            : 
     329         [ #  # ]:          0 :         if (!insn->x86_64)
     330                 :            :                 return 0;
     331         [ #  # ]:          0 :         if (!modrm->got)
     332                 :          0 :                 insn_get_modrm(insn);
     333                 :            :         /*
     334                 :            :          * For rip-relative instructions, the mod field (top 2 bits)
     335                 :            :          * is zero and the r/m field (bottom 3 bits) is 0x5.
     336                 :            :          */
     337   [ #  #  #  # ]:          0 :         return (modrm->nbytes && (modrm->value & 0xc7) == 0x5);
     338                 :            : }
     339                 :            : 
     340                 :            : /**
     341                 :            :  * insn_get_sib() - Get the SIB byte of instruction
     342                 :            :  * @insn:       &struct insn containing instruction
     343                 :            :  *
     344                 :            :  * If necessary, first collects the instruction up to and including the
     345                 :            :  * ModRM byte.
     346                 :            :  */
     347                 :        605 : void insn_get_sib(struct insn *insn)
     348                 :            : {
     349                 :        605 :         insn_byte_t modrm;
     350                 :            : 
     351         [ +  - ]:        605 :         if (insn->sib.got)
     352                 :            :                 return;
     353         [ +  - ]:        605 :         if (!insn->modrm.got)
     354                 :        605 :                 insn_get_modrm(insn);
     355         [ -  + ]:        605 :         if (insn->modrm.nbytes) {
     356                 :          0 :                 modrm = (insn_byte_t)insn->modrm.value;
     357         [ #  # ]:          0 :                 if (insn->addr_bytes != 2 &&
     358   [ #  #  #  # ]:          0 :                     X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) {
     359         [ #  # ]:          0 :                         insn->sib.value = get_next(insn_byte_t, insn);
     360                 :          0 :                         insn->sib.nbytes = 1;
     361                 :            :                 }
     362                 :            :         }
     363                 :        605 :         insn->sib.got = 1;
     364                 :            : 
     365                 :        605 : err_out:
     366                 :            :         return;
     367                 :            : }
     368                 :            : 
     369                 :            : 
     370                 :            : /**
     371                 :            :  * insn_get_displacement() - Get the displacement of instruction
     372                 :            :  * @insn:       &struct insn containing instruction
     373                 :            :  *
     374                 :            :  * If necessary, first collects the instruction up to and including the
     375                 :            :  * SIB byte.
     376                 :            :  * Displacement value is sign-expanded.
     377                 :            :  */
     378                 :        605 : void insn_get_displacement(struct insn *insn)
     379                 :            : {
     380                 :        605 :         insn_byte_t mod, rm, base;
     381                 :            : 
     382         [ +  - ]:        605 :         if (insn->displacement.got)
     383                 :            :                 return;
     384         [ +  - ]:        605 :         if (!insn->sib.got)
     385                 :        605 :                 insn_get_sib(insn);
     386         [ +  - ]:        605 :         if (insn->modrm.nbytes) {
     387                 :            :                 /*
     388                 :            :                  * Interpreting the modrm byte:
     389                 :            :                  * mod = 00 - no displacement fields (exceptions below)
     390                 :            :                  * mod = 01 - 1-byte displacement field
     391                 :            :                  * mod = 10 - displacement field is 4 bytes, or 2 bytes if
     392                 :            :                  *      address size = 2 (0x67 prefix in 32-bit mode)
     393                 :            :                  * mod = 11 - no memory operand
     394                 :            :                  *
     395                 :            :                  * If address size = 2...
     396                 :            :                  * mod = 00, r/m = 110 - displacement field is 2 bytes
     397                 :            :                  *
     398                 :            :                  * If address size != 2...
     399                 :            :                  * mod != 11, r/m = 100 - SIB byte exists
     400                 :            :                  * mod = 00, SIB base = 101 - displacement field is 4 bytes
     401                 :            :                  * mod = 00, r/m = 101 - rip-relative addressing, displacement
     402                 :            :                  *      field is 4 bytes
     403                 :            :                  */
     404                 :          0 :                 mod = X86_MODRM_MOD(insn->modrm.value);
     405                 :          0 :                 rm = X86_MODRM_RM(insn->modrm.value);
     406                 :          0 :                 base = X86_SIB_BASE(insn->sib.value);
     407         [ #  # ]:          0 :                 if (mod == 3)
     408                 :          0 :                         goto out;
     409         [ #  # ]:          0 :                 if (mod == 1) {
     410         [ #  # ]:          0 :                         insn->displacement.value = get_next(signed char, insn);
     411                 :          0 :                         insn->displacement.nbytes = 1;
     412         [ #  # ]:          0 :                 } else if (insn->addr_bytes == 2) {
     413   [ #  #  #  # ]:          0 :                         if ((mod == 0 && rm == 6) || mod == 2) {
     414                 :          0 :                                 insn->displacement.value =
     415         [ #  # ]:          0 :                                          get_next(short, insn);
     416                 :          0 :                                 insn->displacement.nbytes = 2;
     417                 :            :                         }
     418                 :            :                 } else {
     419   [ #  #  #  # ]:          0 :                         if ((mod == 0 && rm == 5) || mod == 2 ||
     420         [ #  # ]:          0 :                             (mod == 0 && base == 5)) {
     421         [ #  # ]:          0 :                                 insn->displacement.value = get_next(int, insn);
     422                 :          0 :                                 insn->displacement.nbytes = 4;
     423                 :            :                         }
     424                 :            :                 }
     425                 :            :         }
     426                 :        605 : out:
     427                 :        605 :         insn->displacement.got = 1;
     428                 :            : 
     429                 :        605 : err_out:
     430                 :            :         return;
     431                 :            : }
     432                 :            : 
     433                 :            : /* Decode moffset16/32/64. Return 0 if failed */
     434                 :          0 : static int __get_moffset(struct insn *insn)
     435                 :            : {
     436   [ #  #  #  # ]:          0 :         switch (insn->addr_bytes) {
     437                 :          0 :         case 2:
     438         [ #  # ]:          0 :                 insn->moffset1.value = get_next(short, insn);
     439                 :          0 :                 insn->moffset1.nbytes = 2;
     440                 :          0 :                 break;
     441                 :          0 :         case 4:
     442         [ #  # ]:          0 :                 insn->moffset1.value = get_next(int, insn);
     443                 :          0 :                 insn->moffset1.nbytes = 4;
     444                 :          0 :                 break;
     445                 :          0 :         case 8:
     446         [ #  # ]:          0 :                 insn->moffset1.value = get_next(int, insn);
     447                 :          0 :                 insn->moffset1.nbytes = 4;
     448         [ #  # ]:          0 :                 insn->moffset2.value = get_next(int, insn);
     449                 :          0 :                 insn->moffset2.nbytes = 4;
     450                 :          0 :                 break;
     451                 :          0 :         default:        /* opnd_bytes must be modified manually */
     452                 :          0 :                 goto err_out;
     453                 :            :         }
     454                 :          0 :         insn->moffset1.got = insn->moffset2.got = 1;
     455                 :            : 
     456                 :          0 :         return 1;
     457                 :            : 
     458                 :            : err_out:
     459                 :            :         return 0;
     460                 :            : }
     461                 :            : 
     462                 :            : /* Decode imm v32(Iz). Return 0 if failed */
     463                 :        451 : static int __get_immv32(struct insn *insn)
     464                 :            : {
     465      [ -  +  - ]:        451 :         switch (insn->opnd_bytes) {
     466                 :          0 :         case 2:
     467         [ #  # ]:          0 :                 insn->immediate.value = get_next(short, insn);
     468                 :          0 :                 insn->immediate.nbytes = 2;
     469                 :          0 :                 break;
     470                 :        451 :         case 4:
     471                 :            :         case 8:
     472         [ -  + ]:        451 :                 insn->immediate.value = get_next(int, insn);
     473                 :        451 :                 insn->immediate.nbytes = 4;
     474                 :        451 :                 break;
     475                 :          0 :         default:        /* opnd_bytes must be modified manually */
     476                 :          0 :                 goto err_out;
     477                 :            :         }
     478                 :            : 
     479                 :            :         return 1;
     480                 :            : 
     481                 :        451 : err_out:
     482                 :            :         return 0;
     483                 :            : }
     484                 :            : 
     485                 :            : /* Decode imm v64(Iv/Ov), Return 0 if failed */
     486                 :          0 : static int __get_immv(struct insn *insn)
     487                 :            : {
     488   [ #  #  #  # ]:          0 :         switch (insn->opnd_bytes) {
     489                 :          0 :         case 2:
     490         [ #  # ]:          0 :                 insn->immediate1.value = get_next(short, insn);
     491                 :          0 :                 insn->immediate1.nbytes = 2;
     492                 :          0 :                 break;
     493                 :          0 :         case 4:
     494         [ #  # ]:          0 :                 insn->immediate1.value = get_next(int, insn);
     495                 :          0 :                 insn->immediate1.nbytes = 4;
     496                 :          0 :                 break;
     497                 :          0 :         case 8:
     498         [ #  # ]:          0 :                 insn->immediate1.value = get_next(int, insn);
     499                 :          0 :                 insn->immediate1.nbytes = 4;
     500         [ #  # ]:          0 :                 insn->immediate2.value = get_next(int, insn);
     501                 :          0 :                 insn->immediate2.nbytes = 4;
     502                 :          0 :                 break;
     503                 :          0 :         default:        /* opnd_bytes must be modified manually */
     504                 :          0 :                 goto err_out;
     505                 :            :         }
     506                 :          0 :         insn->immediate1.got = insn->immediate2.got = 1;
     507                 :            : 
     508                 :          0 :         return 1;
     509                 :            : err_out:
     510                 :            :         return 0;
     511                 :            : }
     512                 :            : 
     513                 :            : /* Decode ptr16:16/32(Ap) */
     514                 :          0 : static int __get_immptr(struct insn *insn)
     515                 :            : {
     516   [ #  #  #  # ]:          0 :         switch (insn->opnd_bytes) {
     517                 :          0 :         case 2:
     518         [ #  # ]:          0 :                 insn->immediate1.value = get_next(short, insn);
     519                 :          0 :                 insn->immediate1.nbytes = 2;
     520                 :          0 :                 break;
     521                 :          0 :         case 4:
     522         [ #  # ]:          0 :                 insn->immediate1.value = get_next(int, insn);
     523                 :          0 :                 insn->immediate1.nbytes = 4;
     524                 :          0 :                 break;
     525                 :            :         case 8:
     526                 :            :                 /* ptr16:64 is not exist (no segment) */
     527                 :            :                 return 0;
     528                 :          0 :         default:        /* opnd_bytes must be modified manually */
     529                 :          0 :                 goto err_out;
     530                 :            :         }
     531         [ #  # ]:          0 :         insn->immediate2.value = get_next(unsigned short, insn);
     532                 :          0 :         insn->immediate2.nbytes = 2;
     533                 :          0 :         insn->immediate1.got = insn->immediate2.got = 1;
     534                 :            : 
     535                 :          0 :         return 1;
     536                 :            : err_out:
     537                 :            :         return 0;
     538                 :            : }
     539                 :            : 
     540                 :            : /**
     541                 :            :  * insn_get_immediate() - Get the immediates of instruction
     542                 :            :  * @insn:       &struct insn containing instruction
     543                 :            :  *
     544                 :            :  * If necessary, first collects the instruction up to and including the
     545                 :            :  * displacement bytes.
     546                 :            :  * Basically, most of immediates are sign-expanded. Unsigned-value can be
     547                 :            :  * get by bit masking with ((1 << (nbytes * 8)) - 1)
     548                 :            :  */
     549                 :        605 : void insn_get_immediate(struct insn *insn)
     550                 :            : {
     551         [ +  - ]:        605 :         if (insn->immediate.got)
     552                 :            :                 return;
     553         [ +  - ]:        605 :         if (!insn->displacement.got)
     554                 :        605 :                 insn_get_displacement(insn);
     555                 :            : 
     556         [ -  + ]:        605 :         if (inat_has_moffset(insn->attr)) {
     557         [ #  # ]:          0 :                 if (!__get_moffset(insn))
     558                 :          0 :                         goto err_out;
     559                 :          0 :                 goto done;
     560                 :            :         }
     561                 :            : 
     562         [ +  + ]:        605 :         if (!inat_has_immediate(insn->attr))
     563                 :            :                 /* no immediates */
     564                 :        154 :                 goto done;
     565                 :            : 
     566   [ -  -  -  -  :        451 :         switch (inat_immediate_size(insn->attr)) {
             -  +  -  - ]
     567                 :          0 :         case INAT_IMM_BYTE:
     568         [ #  # ]:          0 :                 insn->immediate.value = get_next(signed char, insn);
     569                 :          0 :                 insn->immediate.nbytes = 1;
     570                 :          0 :                 break;
     571                 :          0 :         case INAT_IMM_WORD:
     572         [ #  # ]:          0 :                 insn->immediate.value = get_next(short, insn);
     573                 :          0 :                 insn->immediate.nbytes = 2;
     574                 :          0 :                 break;
     575                 :          0 :         case INAT_IMM_DWORD:
     576         [ #  # ]:          0 :                 insn->immediate.value = get_next(int, insn);
     577                 :          0 :                 insn->immediate.nbytes = 4;
     578                 :          0 :                 break;
     579                 :          0 :         case INAT_IMM_QWORD:
     580         [ #  # ]:          0 :                 insn->immediate1.value = get_next(int, insn);
     581                 :          0 :                 insn->immediate1.nbytes = 4;
     582         [ #  # ]:          0 :                 insn->immediate2.value = get_next(int, insn);
     583                 :          0 :                 insn->immediate2.nbytes = 4;
     584                 :          0 :                 break;
     585                 :          0 :         case INAT_IMM_PTR:
     586         [ #  # ]:          0 :                 if (!__get_immptr(insn))
     587                 :          0 :                         goto err_out;
     588                 :            :                 break;
     589                 :        451 :         case INAT_IMM_VWORD32:
     590         [ -  + ]:        451 :                 if (!__get_immv32(insn))
     591                 :          0 :                         goto err_out;
     592                 :            :                 break;
     593                 :          0 :         case INAT_IMM_VWORD:
     594         [ #  # ]:          0 :                 if (!__get_immv(insn))
     595                 :          0 :                         goto err_out;
     596                 :            :                 break;
     597                 :          0 :         default:
     598                 :            :                 /* Here, insn must have an immediate, but failed */
     599                 :          0 :                 goto err_out;
     600                 :            :         }
     601         [ +  - ]:        451 :         if (inat_has_second_immediate(insn->attr)) {
     602         [ #  # ]:          0 :                 insn->immediate2.value = get_next(signed char, insn);
     603                 :          0 :                 insn->immediate2.nbytes = 1;
     604                 :            :         }
     605                 :        451 : done:
     606                 :        605 :         insn->immediate.got = 1;
     607                 :            : 
     608                 :        605 : err_out:
     609                 :            :         return;
     610                 :            : }
     611                 :            : 
     612                 :            : /**
     613                 :            :  * insn_get_length() - Get the length of instruction
     614                 :            :  * @insn:       &struct insn containing instruction
     615                 :            :  *
     616                 :            :  * If necessary, first collects the instruction up to and including the
     617                 :            :  * immediates bytes.
     618                 :            :  */
     619                 :        605 : void insn_get_length(struct insn *insn)
     620                 :            : {
     621         [ +  - ]:        605 :         if (insn->length)
     622                 :            :                 return;
     623         [ +  - ]:        605 :         if (!insn->immediate.got)
     624                 :        605 :                 insn_get_immediate(insn);
     625                 :        605 :         insn->length = (unsigned char)((unsigned long)insn->next_byte
     626                 :        605 :                                      - (unsigned long)insn->kaddr);
     627                 :            : }

Generated by: LCOV version 1.14