LCOV - code coverage report
Current view: directory - src/trusted/validator/x86/ncval_seg_sfi - ncdecode.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 388 295 76.0 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * ncdecode.c - table driven decoder for Native Client
       9                 :  *
      10                 :  * Most x86 decoders I've looked at are big case statements. While
      11                 :  * this organization is fairly transparent and obvious, it tends to
      12                 :  * lead to messy control flow (gotos, etc.) that make the decoder
      13                 :  * more complicated, hence harder to maintain and harder to validate.
      14                 :  *
      15                 :  * This decoder is table driven, which will hopefully result in
      16                 :  * substantially less code. Although the code+tables may be more
      17                 :  * lines of code than a decoder built around a switch statement,
      18                 :  * the smaller amount of actual procedural code and the regular
      19                 :  * structure of the tables should make it easier to understand,
      20                 :  * debug, and easier to become confident the decoder is correct.
      21                 :  *
      22                 :  * As it is specialized to Native Client, this decoder can also
      23                 :  * benefit from any exclusions or simplifications we decide to
      24                 :  * make in the dialect of x86 machine code accepted by Native
      25                 :  * Client. Any such simplifications should ultimately be easily
      26                 :  * recognized by inspection of the decoder configuration tables.
      27                 :  * ALSO, the decoder mostly needs to worry about accurate
      28                 :  * instruction lengths and finding opcodes. It does not need
      29                 :  * to completely resolve the operands of all instructions.
      30                 :  */
      31                 : 
      32                 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h"
      33                 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_aux.h"
      34                 : 
      35                 : #include <stdio.h>
      36                 : #include <assert.h>
      37                 : 
      38                 : #if NACL_TARGET_SUBARCH == 64
      39                 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdecodetab_64.h"
      40                 : #else
      41                 : #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdecodetab_32.h"
      42                 : #endif
      43                 : 
      44                 : /* To turn on debugging of instruction decoding, change value of
      45                 :  * DEBUGGING to 1.
      46                 :  */
      47                 : #define DEBUGGING 0
      48                 : 
      49                 : #include "native_client/src/shared/utils/debugging.h"
      50                 : 
      51                 : #include "native_client/src/trusted/validator/x86/ncinstbuffer_inl.c"
      52                 : #include "native_client/src/trusted/validator/x86/x86_insts_inl.c"
      53                 : 
      54                 : /* Generates a print name for the given NCDecodeImmediateType. */
      55               0 : static const char* NCDecodeImmediateTypeName(NCDecodeImmediateType type) {
      56                 :   DEBUG_OR_ERASE(
      57                 :       switch(type) {
      58                 :         case IMM_UNKNOWN: return "IMM_UNKNOWN";
      59                 :         case IMM_NONE: return "IMM_NONE";
      60                 :         case IMM_FIXED1: return "IMM_FIXED1";
      61                 :         case IMM_FIXED2: return "IMM_FIXED2";
      62                 :         case IMM_FIXED3: return "IMM_FIXED3";
      63                 :         case IMM_FIXED4: return "IMM_FIXED4";
      64                 :         case IMM_DATAV: return "IMM_DATAV";
      65                 :         case IMM_ADDRV: return "IMM_ADDRV";
      66                 :         case IMM_GROUP3_F6: return "IMM_GROUP3_F6";
      67                 :         case IMM_GROUP3_F7: return "IMM_GROUP3_F7";
      68                 :         case IMM_FARPTR: return "IMM_FARPTR";
      69                 :         case IMM_MOV_DATAV: return "IMM_MOV_DATAV";
      70                 :         default: assert(0);
      71                 :       });
      72                 :   /* NOTREACHED */
      73               0 :   return NULL;
      74               0 : }
      75                 : 
      76                 : /* Prints out the contents of the given OpInfo. Should only be called
      77                 :  * inside a DEBUG macro (i.e. for debugging only).
      78                 :  */
      79               0 : static void PrintOpInfo(const struct OpInfo* info) {
      80                 :   DEBUG_OR_ERASE(printf("opinfo(%s, hasmrm=%u, immtype=%s, opinmrm=%d)\n",
      81                 :                         NaClInstTypeString(info->insttype),
      82                 :                         info->hasmrmbyte,
      83                 :                         NCDecodeImmediateTypeName(info->immtype),
      84                 :                         info->opinmrm));
      85               0 : }
      86                 : 
      87                 : /* later this will make decoding x87 instructions a bit more concise. */
      88                 : static const struct OpInfo* kDecodeX87Op[8] = { kDecode87D8,
      89                 :                                                 kDecode87D9,
      90                 :                                                 kDecode87DA,
      91                 :                                                 kDecode87DB,
      92                 :                                                 kDecode87DC,
      93                 :                                                 kDecode87DD,
      94                 :                                                 kDecode87DE,
      95                 :                                                 kDecode87DF };
      96                 : 
      97               0 : static Bool NullDecoderAction(const struct NCDecoderInst* dinst) {
      98                 :   UNREFERENCED_PARAMETER(dinst);
      99               0 :   return TRUE;
     100               0 : }
     101               2 : static void NullDecoderMethod(struct NCDecoderState* dstate) {
     102                 :   UNREFERENCED_PARAMETER(dstate);
     103               2 : }
     104                 : 
     105                 : /* API to virtual methods of a decoder state. */
     106               2 : void NCDecoderStateNewSegment(NCDecoderState* tthis) {
     107               2 :   (tthis->new_segment_fn)(tthis);
     108               2 : }
     109                 : 
     110                 : static Bool NCDecoderStateApplyAction(NCDecoderState* tthis,
     111               2 :                                       NCDecoderInst* dinst) {
     112               2 :   return (tthis->action_fn)(dinst);
     113               2 : }
     114                 : 
     115               2 : static void NCDecoderStateSegmentationError(NCDecoderState* tthis) {
     116               2 :   (tthis->segmentation_error_fn)(tthis);
     117               2 : }
     118                 : 
     119               0 : static void NCDecoderStateInternalError(NCDecoderState* tthis) {
     120               0 :   (tthis->internal_error_fn)(tthis);
     121               0 : }
     122                 : 
     123                 : /* Error Condition Handling */
     124               2 : static void ErrorSegmentation(NCDecoderInst* dinst) {
     125               2 :   NCDecoderState* dstate = dinst->dstate;
     126               2 :   NaClErrorReporter* reporter = dstate->error_reporter;
     127               2 :   (*reporter->printf)(dstate->error_reporter, "ErrorSegmentation\n");
     128                 :   /* When the decoder is used by the NaCl validator    */
     129                 :   /* the validator provides an error handler that does */
     130                 :   /* the necessary bookeeping to track these errors.   */
     131               2 :   NCDecoderStateSegmentationError(dstate);
     132               2 : }
     133                 : 
     134               0 : static void ErrorInternal(NCDecoderInst* dinst) {
     135               0 :   NCDecoderState* dstate = dinst->dstate;
     136               0 :   NaClErrorReporter* reporter = dstate->error_reporter;
     137               0 :   (*reporter->printf)(reporter, "ErrorInternal\n");
     138                 :   /* When the decoder is used by the NaCl validator    */
     139                 :   /* the validator provides an error handler that does */
     140                 :   /* the necessary bookeeping to track these errors.   */
     141               0 :   NCDecoderStateInternalError(dstate);
     142               0 : }
     143                 : 
     144                 : /* Defines how to handle errors found while parsing the memory segment. */
     145                 : static void NCRemainingMemoryInternalError(NCRemainingMemoryError error,
     146               2 :                                            struct NCRemainingMemory* memory) {
     147                 :   /* Don't do anything for memory overflow! Let NCDecodeSegment generate
     148                 :    * the corresponding segmentation error. This allows us to back out overflow
     149                 :    * if a predefined nop is matched.
     150                 :    */
     151               2 :   if (NCRemainingMemoryOverflow != error) {
     152               0 :     NCDecoderState* dstate = (NCDecoderState*) memory->error_fn_state;
     153               0 :     NCRemainingMemoryReportError(error, memory);
     154               0 :     ErrorInternal(&dstate->inst_buffer[dstate->cur_inst_index]);
     155                 :   }
     156               2 : }
     157                 : 
     158               2 : static INLINE void InitDecoder(struct NCDecoderInst* dinst) {
     159               2 :   NCInstBytesInitInline(&dinst->inst.bytes);
     160               2 :   dinst->inst.prefixbytes = 0;
     161               2 :   dinst->inst.prefixmask = 0;
     162               2 :   dinst->inst.opcode_prefixmask = 0;
     163               2 :   dinst->inst.num_opbytes = 1;  /* unless proven otherwise. */
     164               2 :   dinst->inst.hassibbyte = 0;
     165               2 :   dinst->inst.mrm = 0;
     166               2 :   dinst->inst.immtype = IMM_UNKNOWN;
     167               2 :   dinst->inst.immbytes = 0;
     168               2 :   dinst->inst.dispbytes = 0;
     169               2 :   dinst->inst.rexprefix = 0;
     170               2 :   dinst->inst.lock_prefix_index = kNoLockPrefixIndex;
     171               2 :   dinst->opinfo = NULL;
     172               2 : }
     173                 : 
     174                 : /* Returns the number of bytes defined for the operand of the instruction. */
     175               2 : static int ExtractOperandSize(NCDecoderInst* dinst) {
     176                 :   if (NACL_TARGET_SUBARCH == 64 &&
     177               2 :       dinst->inst.rexprefix && dinst->inst.rexprefix & 0x8) {
     178               0 :     return 8;
     179                 :   }
     180               2 :   if (dinst->inst.prefixmask & kPrefixDATA16) {
     181               2 :     return 2;
     182                 :   }
     183               2 :   return 4;
     184               2 : }
     185                 : 
     186                 : /* at most four prefix bytes are allowed */
     187               2 : static void ConsumePrefixBytes(struct NCDecoderInst* dinst) {
     188                 :   uint8_t nb;
     189                 :   int ii;
     190                 :   uint32_t prefix_form;
     191                 : 
     192               2 :   for (ii = 0; ii < kMaxPrefixBytes; ++ii) {
     193               2 :     nb = NCRemainingMemoryGetNext(&dinst->dstate->memory);
     194               2 :     prefix_form = kPrefixTable[nb];
     195               2 :     if (prefix_form == 0) return;
     196               2 :     DEBUG( printf("Consume prefix[%d]: %02x => %x\n", ii, nb, prefix_form) );
     197               2 :     dinst->inst.prefixmask |= prefix_form;
     198               2 :     dinst->inst.prefixmask |= kPrefixTable[nb];
     199               2 :     dinst->inst.prefixbytes += 1;
     200               2 :     NCInstBytesReadInline(&dinst->inst.bytes);
     201               2 :     DEBUG( printf("  prefix mask: %08x\n", dinst->inst.prefixmask) );
     202               2 :     if (NACL_TARGET_SUBARCH == 64 && prefix_form == kPrefixREX) {
     203               0 :       dinst->inst.rexprefix = nb;
     204                 :       /* REX prefix must be last prefix. */
     205               0 :       return;
     206                 :     }
     207               2 :     if (prefix_form == kPrefixLOCK) {
     208                 :       /* Note: we don't have to worry about duplicates, since
     209                 :        * ValidatePrefixes in ncvalidate.c will not allow such
     210                 :        * a possibility.
     211                 :        */
     212               2 :       dinst->inst.lock_prefix_index = (uint8_t) ii;
     213                 :     }
     214               2 :   }
     215               2 : }
     216                 : 
     217                 : static const struct OpInfo* GetExtendedOpInfo(NCDecoderInst* dinst,
     218               2 :                                               uint8_t opbyte2) {
     219                 :   uint32_t pm;
     220               2 :   pm = dinst->inst.prefixmask;
     221               2 :   if ((pm & (kPrefixDATA16 | kPrefixREPNE | kPrefixREP)) == 0) {
     222               2 :     return &kDecode0FXXOp[opbyte2];
     223               2 :   } else if (pm & kPrefixDATA16) {
     224               2 :     dinst->inst.prefixmask &= ~kPrefixDATA16;
     225               2 :     dinst->inst.opcode_prefixmask = kPrefixDATA16;
     226               2 :     return &kDecode660FXXOp[opbyte2];
     227               2 :   } else if (pm & kPrefixREPNE) {
     228               1 :     dinst->inst.prefixmask &= ~kPrefixREPNE;
     229               1 :     dinst->inst.opcode_prefixmask = kPrefixREPNE;
     230               1 :     return &kDecodeF20FXXOp[opbyte2];
     231               2 :   } else if (pm & kPrefixREP) {
     232               2 :     dinst->inst.prefixmask &= ~kPrefixREP;
     233               2 :     dinst->inst.opcode_prefixmask = kPrefixREP;
     234               2 :     return &kDecodeF30FXXOp[opbyte2];
     235                 :   }
     236               0 :   ErrorInternal(dinst);
     237               0 :   return dinst->opinfo;
     238               2 : }
     239                 : 
     240               2 : static void GetX87OpInfo(NCDecoderInst* dinst) {
     241                 :   /* WAIT is an x87 instruction but not in the coproc opcode space. */
     242                 :   uint8_t op1 = NCInstBytesByteInline(&dinst->inst_bytes,
     243               2 :                                       dinst->inst.prefixbytes);
     244               2 :   if (op1 < kFirstX87Opcode || op1 > kLastX87Opcode) {
     245               0 :     if (op1 != kWAITOp) ErrorInternal(dinst);
     246               0 :     return;
     247                 :   }
     248               2 :   dinst->opinfo = &kDecodeX87Op[op1 - kFirstX87Opcode][dinst->inst.mrm];
     249                 :   DEBUG( printf("NACL_X87 op1 = %02x, ", op1);
     250               2 :          PrintOpInfo(dinst->opinfo) );
     251               2 : }
     252                 : 
     253               2 : static void ConsumeOpcodeBytes(NCDecoderInst* dinst) {
     254               2 :   uint8_t opcode = NCInstBytesReadInline(&dinst->inst.bytes);
     255               2 :   dinst->opinfo = &kDecode1ByteOp[opcode];
     256                 :   DEBUG( printf("NACLi_1BYTE: opcode = %02x, ", opcode);
     257               2 :          PrintOpInfo(dinst->opinfo) );
     258               2 :   if (opcode == kTwoByteOpcodeByte1) {
     259               2 :     uint8_t opcode2 = NCInstBytesReadInline(&dinst->inst.bytes);
     260               2 :     dinst->opinfo = GetExtendedOpInfo(dinst, opcode2);
     261                 :     DEBUG( printf("NACLi_2BYTE: opcode2 = %02x, ", opcode2);
     262               2 :            PrintOpInfo(dinst->opinfo) );
     263               2 :     dinst->inst.num_opbytes = 2;
     264               2 :     if (dinst->opinfo->insttype == NACLi_3BYTE) {
     265               1 :       uint8_t opcode3 = NCInstBytesReadInline(&dinst->inst.bytes);
     266                 :       uint32_t pm;
     267               1 :       pm = dinst->inst.opcode_prefixmask;
     268               1 :       dinst->inst.num_opbytes = 3;
     269                 : 
     270               1 :       DEBUG( printf("NACLi_3BYTE: opcode3 = %02x, ", opcode3) );
     271               1 :       switch (opcode2) {
     272                 :       case 0x38:        /* SSSE3, SSE4 */
     273               1 :         if (pm & kPrefixDATA16) {
     274               1 :           dinst->opinfo = &kDecode660F38Op[opcode3];
     275               1 :         } else if (pm & kPrefixREPNE) {
     276               1 :           dinst->opinfo = &kDecodeF20F38Op[opcode3];
     277               0 :         } else if (pm == 0) {
     278               0 :           dinst->opinfo = &kDecode0F38Op[opcode3];
     279               0 :         } else {
     280                 :           /* Other prefixes like F3 cause an undefined instruction error. */
     281                 :           /* Note from decoder table that NACLi_3BYTE is only used with   */
     282                 :           /* data16 and repne prefixes.                                   */
     283               0 :           ErrorInternal(dinst);
     284                 :         }
     285               1 :         break;
     286                 :       case 0x3A:        /* SSSE3, SSE4 */
     287               1 :         if (pm & kPrefixDATA16) {
     288               1 :           dinst->opinfo = &kDecode660F3AOp[opcode3];
     289               0 :         } else if (pm == 0) {
     290               0 :           dinst->opinfo = &kDecode0F3AOp[opcode3];
     291               0 :         } else {
     292                 :           /* Other prefixes like F3 cause an undefined instruction error. */
     293                 :           /* Note from decoder table that NACLi_3BYTE is only used with   */
     294                 :           /* data16 and repne prefixes.                                   */
     295               0 :           ErrorInternal(dinst);
     296                 :         }
     297               1 :         break;
     298                 :       default:
     299                 :         /* if this happens there is a decoding table bug */
     300               0 :         ErrorInternal(dinst);
     301                 :         break;
     302                 :       }
     303               1 :       DEBUG( PrintOpInfo(dinst->opinfo) );
     304                 :     }
     305                 :   }
     306               2 :   dinst->inst.immtype = dinst->opinfo->immtype;
     307               2 : }
     308                 : 
     309               2 : static void ConsumeModRM(NCDecoderInst* dinst) {
     310               2 :   if (dinst->opinfo->hasmrmbyte != 0) {
     311               2 :     const uint8_t mrm = NCInstBytesReadInline(&dinst->inst.bytes);
     312               2 :     DEBUG( printf("Mod/RM byte: %02x\n", mrm) );
     313               2 :     dinst->inst.mrm = mrm;
     314                 :     if (dinst->opinfo->insttype == NACLi_X87 ||
     315               2 :         dinst->opinfo->insttype == NACLi_X87_FSINCOS) {
     316               2 :       GetX87OpInfo(dinst);
     317                 :     }
     318               2 :     if (dinst->opinfo->opinmrm) {
     319                 :       const struct OpInfo* mopinfo =
     320               2 :         &kDecodeModRMOp[dinst->opinfo->opinmrm][modrm_opcodeInline(mrm)];
     321               2 :       dinst->opinfo = mopinfo;
     322                 :       DEBUG( printf("NACLi_opinmrm: modrm.opcode = %x, ",
     323                 :                     modrm_opcodeInline(mrm));
     324               2 :              PrintOpInfo(dinst->opinfo) );
     325               2 :       if (dinst->inst.immtype == IMM_UNKNOWN) {
     326               0 :         assert(0);
     327               0 :         dinst->inst.immtype = mopinfo->immtype;
     328                 :       }
     329                 :       /* handle weird case for 0xff TEST Ib/Iv */
     330               2 :       if (modrm_opcodeInline(mrm) == 0) {
     331               2 :         if (dinst->inst.immtype == IMM_GROUP3_F6) {
     332               0 :           dinst->inst.immtype = IMM_FIXED1;
     333                 :         }
     334               2 :         if (dinst->inst.immtype == IMM_GROUP3_F7) {
     335               0 :           dinst->inst.immtype = IMM_DATAV;
     336                 :         }
     337                 :       }
     338                 :       DEBUG( printf("  immtype = %s\n",
     339               2 :                     NCDecodeImmediateTypeName(dinst->inst.immtype)) );
     340                 :     }
     341               2 :     if (dinst->inst.prefixmask & kPrefixADDR16) {
     342               2 :       switch (modrm_modInline(mrm)) {
     343                 :         case 0:
     344               2 :           if (modrm_rmInline(mrm) == 0x06) {
     345               0 :             dinst->inst.dispbytes = 2;        /* disp16 */
     346               0 :           } else {
     347               2 :             dinst->inst.dispbytes = 0;
     348                 :           }
     349               2 :           break;
     350                 :         case 1:
     351               2 :           dinst->inst.dispbytes = 1;           /* disp8 */
     352               2 :           break;
     353                 :         case 2:
     354               1 :           dinst->inst.dispbytes = 2;           /* disp16 */
     355               1 :           break;
     356                 :         case 3:
     357               1 :           dinst->inst.dispbytes = 0;           /* no disp */
     358               1 :           break;
     359                 :         default:
     360               0 :           ErrorInternal(dinst);
     361                 :       }
     362               2 :       dinst->inst.hassibbyte = 0;
     363               2 :     } else {
     364               2 :       switch (modrm_modInline(mrm)) {
     365                 :         case 0:
     366               2 :           if (modrm_rmInline(mrm) == 0x05) {
     367               2 :             dinst->inst.dispbytes = 4;         /* disp32 */
     368               2 :           } else {
     369               2 :             dinst->inst.dispbytes = 0;
     370                 :           }
     371               2 :           break;
     372                 :         case 1:
     373               2 :           dinst->inst.dispbytes = 1;           /* disp8 */
     374               2 :           break;
     375                 :         case 2:
     376               2 :           dinst->inst.dispbytes = 4;           /* disp32 */
     377               2 :           break;
     378                 :         case 3:
     379               2 :           dinst->inst.dispbytes = 0;           /* no disp */
     380               2 :           break;
     381                 :         default:
     382               0 :           ErrorInternal(dinst);
     383                 :       }
     384                 :       dinst->inst.hassibbyte = ((modrm_rmInline(mrm) == 0x04) &&
     385               2 :                                  (modrm_modInline(mrm) != 3));
     386                 :     }
     387                 :   }
     388                 :   DEBUG( printf("  dispbytes = %d, hasibbyte = %d\n",
     389               2 :                 dinst->inst.dispbytes, dinst->inst.hassibbyte) );
     390               2 : }
     391                 : 
     392               2 : static INLINE void ConsumeSIB(NCDecoderInst* dinst) {
     393               2 :   if (dinst->inst.hassibbyte != 0) {
     394               2 :     const uint8_t sib = NCInstBytesReadInline(&dinst->inst.bytes);
     395               2 :     if (sib_base(sib) == 0x05) {
     396               2 :       switch (modrm_modInline(dinst->inst.mrm)) {
     397               2 :       case 0: dinst->inst.dispbytes = 4; break;
     398               2 :       case 1: dinst->inst.dispbytes = 1; break;
     399               0 :       case 2: dinst->inst.dispbytes = 4; break;
     400                 :       case 3:
     401                 :       default:
     402               0 :         ErrorInternal(dinst);
     403                 :       }
     404                 :     }
     405                 :     DEBUG( printf("sib byte: %02x, dispbytes = %d\n",
     406               2 :                   sib, dinst->inst.dispbytes) );
     407                 :   }
     408               2 : }
     409                 : 
     410               2 : static INLINE void ConsumeID(NCDecoderInst* dinst) {
     411               2 :   if (dinst->inst.immtype == IMM_UNKNOWN) {
     412               0 :     ErrorInternal(dinst);
     413                 :   }
     414                 :   /* NOTE: NaCl allows at most one prefix byte (for 32-bit mode) */
     415               2 :   if (dinst->inst.immtype == IMM_MOV_DATAV) {
     416               2 :     dinst->inst.immbytes = ExtractOperandSize(dinst);
     417               2 :   } else if (dinst->inst.prefixmask & kPrefixDATA16) {
     418               2 :     dinst->inst.immbytes = kImmTypeToSize66[dinst->inst.immtype];
     419               2 :   } else if (dinst->inst.prefixmask & kPrefixADDR16) {
     420               2 :     dinst->inst.immbytes = kImmTypeToSize67[dinst->inst.immtype];
     421               2 :   } else {
     422               2 :     dinst->inst.immbytes = kImmTypeToSize[dinst->inst.immtype];
     423                 :   }
     424                 :   NCInstBytesReadBytesInline((ssize_t) dinst->inst.immbytes,
     425               2 :                              &dinst->inst.bytes);
     426                 :   NCInstBytesReadBytesInline((ssize_t) dinst->inst.dispbytes,
     427               2 :                              &dinst->inst.bytes);
     428                 :   DEBUG(printf("ID: %d disp bytes, %d imm bytes\n",
     429               2 :                dinst->inst.dispbytes, dinst->inst.immbytes));
     430               2 : }
     431                 : 
     432                 : /* Actually this routine is special for 3DNow instructions */
     433               2 : static INLINE void MaybeGet3ByteOpInfo(NCDecoderInst* dinst) {
     434               2 :   if (dinst->opinfo->insttype == NACLi_3DNOW) {
     435                 :     uint8_t opbyte1 = NCInstBytesByteInline(&dinst->inst_bytes,
     436               1 :                                       dinst->inst.prefixbytes);
     437                 :     uint8_t opbyte2 = NCInstBytesByteInline(&dinst->inst_bytes,
     438               1 :                                       dinst->inst.prefixbytes + 1);
     439                 :     if (opbyte1 == kTwoByteOpcodeByte1 &&
     440               1 :         opbyte2 == k3DNowOpcodeByte2) {
     441                 :       uint8_t immbyte =
     442                 :           NCInstBytesByteInline(&dinst->inst_bytes,
     443               1 :                                 dinst->inst.bytes.length - 1);
     444               1 :       dinst->opinfo = &kDecode0F0FOp[immbyte];
     445                 :       DEBUG( printf(
     446                 :                  "NACLi_3DNOW: byte1 = %02x, byte2 = %02x, immbyte = %02x,\n  ",
     447                 :                  opbyte1, opbyte2, immbyte);
     448               1 :              PrintOpInfo(dinst->opinfo) );
     449                 :     }
     450                 :   }
     451               2 : }
     452                 : 
     453                 : /* Gets an instruction nindex away from the given instruction.
     454                 :  * WARNING: Does not do bounds checking, other than rolling the
     455                 :  * index as needed to stay within the (circular) instruction buffer.
     456                 :  */
     457                 : static NCDecoderInst* NCGetInstDiff(const NCDecoderInst* dinst,
     458               2 :                                       int nindex) {
     459                 :   /* Note: This code also handles increments, so that we can
     460                 :    * use the same code for both.
     461                 :    */
     462               2 :   size_t index = (dinst->inst_index + nindex) % dinst->dstate->inst_buffer_size;
     463               2 :   return &dinst->dstate->inst_buffer[index];
     464               2 : }
     465                 : 
     466                 : struct NCDecoderInst* PreviousInst(const NCDecoderInst* dinst,
     467               0 :                                    int nindex) {
     468               0 :   if ((nindex > 0) && (((size_t) nindex) < dinst->inst_count)) {
     469               0 :     return NCGetInstDiff(dinst, -nindex);
     470                 :   } else {
     471               0 :     return NULL;
     472                 :   }
     473               0 : }
     474                 : 
     475                 : /* Initialize the decoder state fields, assuming constructor parameter
     476                 :  * fields mbase, vbase, size, inst_buffer, and inst_buffer_size have
     477                 :  * already been set.
     478                 :  */
     479               2 : static void NCDecoderStateInitFields(NCDecoderState* this) {
     480                 :   size_t dbindex;
     481               2 :   this->error_reporter = &kNCNullErrorReporter;
     482               2 :   NCRemainingMemoryInit(this->mbase, this->size, &this->memory);
     483               2 :   this->memory.error_fn = NCRemainingMemoryInternalError;
     484               2 :   this->memory.error_fn_state = (void*) this;
     485               2 :   for (dbindex = 0; dbindex < this->inst_buffer_size; ++dbindex) {
     486               2 :     this->inst_buffer[dbindex].dstate = this;
     487               2 :     this->inst_buffer[dbindex].inst_index = dbindex;
     488               2 :     this->inst_buffer[dbindex].inst_count = 1;
     489               2 :     this->inst_buffer[dbindex].inst_addr = 0;
     490               2 :     this->inst_buffer[dbindex].unchanged = FALSE;
     491                 :     NCInstBytesInitMemory(&this->inst_buffer[dbindex].inst.bytes,
     492               2 :                           &this->memory);
     493                 :     NCInstBytesPtrInit((NCInstBytesPtr*) &this->inst_buffer[dbindex].inst_bytes,
     494               2 :                        &this->inst_buffer[dbindex].inst.bytes);
     495               2 :   }
     496               2 :   this->cur_inst_index = 0;
     497               2 : }
     498                 : 
     499                 : void NCDecoderStateConstruct(NCDecoderState* this,
     500                 :                              uint8_t* mbase, NaClPcAddress vbase,
     501                 :                              NaClMemorySize size,
     502                 :                              NCDecoderInst* inst_buffer,
     503               2 :                              size_t inst_buffer_size) {
     504                 : 
     505                 :   /* Start by setting up virtual functions. */
     506               2 :   this->action_fn = NullDecoderAction;
     507               2 :   this->new_segment_fn = NullDecoderMethod;
     508               2 :   this->segmentation_error_fn = NullDecoderMethod;
     509               2 :   this->internal_error_fn = NullDecoderMethod;
     510                 : 
     511                 :   /* Initialize the user-provided fields. */
     512               2 :   this->mbase = mbase;
     513               2 :   this->vbase = vbase;
     514               2 :   this->size = size;
     515               2 :   this->inst_buffer = inst_buffer;
     516               2 :   this->inst_buffer_size = inst_buffer_size;
     517                 : 
     518               2 :   NCDecoderStateInitFields(this);
     519               2 : }
     520                 : 
     521               2 : void NCDecoderStateDestruct(NCDecoderState* this) {
     522                 :   /* Currently, there is nothing to do. */
     523               2 : }
     524                 : 
     525                 : /* "Printable" means the value returned by this function can be used for
     526                 :  * printing user-readable output, but it should not be used to influence if the
     527                 :  * validation algorithm passes or fails.  The validation algorithm should not
     528                 :  * depend on vbase - in other words, it should not depend on where the code is
     529                 :  * being mapped in memory.
     530                 :  */
     531               2 : static INLINE NaClPcAddress NCPrintableVLimit(NCDecoderState *dstate) {
     532               2 :   return dstate->vbase + dstate->size;
     533               2 : }
     534                 : 
     535                 : /* Modify the current instruction pointer to point to the next instruction
     536                 :  * in the ring buffer.  Reset the state of that next instruction.
     537                 :  */
     538               2 : static NCDecoderInst* IncrementInst(NCDecoderInst* inst) {
     539                 :   /* giving PreviousInst a positive number will get NextInst
     540                 :    * better to keep the buffer switching logic in one place
     541                 :    */
     542               2 :   NCDecoderInst* next_inst = NCGetInstDiff(inst, 1);
     543               2 :   next_inst->inst_addr = inst->inst_addr + inst->inst.bytes.length;
     544               2 :   next_inst->dstate->cur_inst_index = next_inst->inst_index;
     545               2 :   next_inst->inst_count = inst->inst_count + 1;
     546               2 :   next_inst->unchanged = FALSE;
     547               2 :   return next_inst;
     548               2 : }
     549                 : 
     550                 : /* Get the i-th byte of the current instruction being parsed. */
     551               2 : static uint8_t GetInstByte(NCDecoderInst* dinst, ssize_t i) {
     552               2 :   if (i < dinst->inst.bytes.length) {
     553               2 :     return dinst->inst.bytes.byte[i];
     554                 :   } else {
     555                 :     return NCRemainingMemoryLookaheadInline(&dinst->dstate->memory,
     556               1 :                                             i - dinst->inst.bytes.length);
     557                 :   }
     558               2 : }
     559                 : 
     560                 : /* Consume a predefined nop byte sequence, if a match can be found.
     561                 :  * Further, if found, replace the currently matched instruction with
     562                 :  * the consumed predefined nop.
     563                 :  */
     564               2 : static void ConsumePredefinedNop(NCDecoderInst* dinst) {
     565                 :   /* Do maximal match of possible nops */
     566               2 :   uint8_t pos = 0;
     567               2 :   struct OpInfo* matching_opinfo = NULL;
     568               2 :   ssize_t matching_length = 0;
     569               2 :   NCNopTrieNode* next = (NCNopTrieNode*) (kNcNopTrieNode + 0);
     570               2 :   uint8_t byte = GetInstByte(dinst, pos);
     571               2 :   while (NULL != next) {
     572               2 :     if (byte == next->matching_byte) {
     573               2 :       DEBUG(printf("NOP match byte: 0x%02x\n", (int) byte));
     574               2 :       byte = GetInstByte(dinst, ++pos);
     575               2 :       if (NULL != next->matching_opinfo) {
     576               1 :         DEBUG(printf("NOP matched rule! %d\n", pos));
     577               1 :         matching_opinfo = next->matching_opinfo;
     578               1 :         matching_length = pos;
     579                 :       }
     580               2 :       next = next->success;
     581               2 :     } else {
     582               2 :       next = next->fail;
     583                 :     }
     584               2 :   }
     585               2 :   if (NULL == matching_opinfo) {
     586               2 :     DEBUG(printf("NOP match failed!\n"));
     587               2 :   } else {
     588               1 :     DEBUG(printf("NOP match succeeds! Using last matched rule.\n"));
     589               1 :     NCRemainingMemoryResetInline(&dinst->dstate->memory);
     590               1 :     InitDecoder(dinst);
     591               1 :     NCInstBytesReadBytesInline(matching_length, &dinst->inst.bytes);
     592               1 :     dinst->opinfo = matching_opinfo;
     593                 :   }
     594               2 : }
     595                 : 
     596                 : /* If we didn't find a good instruction, try to consume one of the
     597                 :  * predefined NOP's.
     598                 :  */
     599               2 : static void MaybeConsumePredefinedNop(NCDecoderInst* dinst) {
     600               2 :   switch (dinst->opinfo->insttype) {
     601                 :     case NACLi_UNDEFINED:
     602                 :     case NACLi_INVALID:
     603                 :     case NACLi_ILLEGAL:
     604               2 :       ConsumePredefinedNop(dinst);
     605                 :       break;
     606                 :     default:
     607                 :       break;
     608                 :   }
     609               2 : }
     610                 : 
     611                 : /* All of the actions needed to read one additional instruction into mstate.
     612                 :  */
     613               2 : void NCConsumeNextInstruction(struct NCDecoderInst* inst) {
     614                 :   DEBUG( printf("Decoding instruction at %"NACL_PRIxNaClPcAddress":\n",
     615               2 :                 inst->inst_addr) );
     616               2 :   InitDecoder(inst);
     617               2 :   ConsumePrefixBytes(inst);
     618               2 :   ConsumeOpcodeBytes(inst);
     619               2 :   ConsumeModRM(inst);
     620               2 :   ConsumeSIB(inst);
     621               2 :   ConsumeID(inst);
     622               2 :   MaybeGet3ByteOpInfo(inst);
     623               2 :   MaybeConsumePredefinedNop(inst);
     624               2 : }
     625                 : 
     626                 : void NCDecoderStateSetErrorReporter(NCDecoderState* this,
     627               2 :                                     NaClErrorReporter* reporter) {
     628               2 :   switch (reporter->supported_reporter) {
     629                 :     case NaClNullErrorReporter:
     630                 :     case NCDecoderInstErrorReporter:
     631               2 :       this->error_reporter = reporter;
     632               2 :       return;
     633                 :     default:
     634                 :       break;
     635                 :   }
     636                 :   (*reporter->printf)(
     637                 :       reporter,
     638                 :       "*** FATAL: using unsupported error reporter! ***\n"
     639                 :       "*** NCDecoderInstErrorReporter expected but found %s***\n",
     640               0 :       NaClErrorReporterSupportedName(reporter->supported_reporter));
     641               0 :   exit(1);
     642               2 : }
     643                 : 
     644                 : static void NCNullErrorPrintInst(NaClErrorReporter* self,
     645               0 :                                  struct NCDecoderInst* inst) {}
     646                 : 
     647                 : NaClErrorReporter kNCNullErrorReporter = {
     648                 :   NaClNullErrorReporter,
     649                 :   NaClNullErrorPrintf,
     650                 :   NaClNullErrorPrintfV,
     651                 :   (NaClPrintInst) NCNullErrorPrintInst,
     652                 : };
     653                 : 
     654               2 : Bool NCDecoderStateDecode(NCDecoderState* this) {
     655               2 :   NCDecoderInst* dinst = &this->inst_buffer[this->cur_inst_index];
     656                 :   DEBUG( printf("DecodeSegment(%p[%"NACL_PRIxNaClPcAddress"])\n",
     657               2 :                 (void*) this->memory.mpc, (NaClPcAddress) this->size) );
     658               2 :   NCDecoderStateNewSegment(this);
     659               2 :   while (dinst->inst_addr < this->size) {
     660               2 :     NCConsumeNextInstruction(dinst);
     661               2 :     if (this->memory.overflow_count) {
     662                 :       NaClPcAddress newpc = (NCPrintableInstructionAddress(dinst)
     663               2 :                              + dinst->inst.bytes.length);
     664                 :       (*this->error_reporter->printf)(
     665                 :           this->error_reporter,
     666                 :           "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress
     667                 :           " (read overflow of %d bytes)\n",
     668               2 :           newpc, NCPrintableVLimit(this), this->memory.overflow_count);
     669               2 :       ErrorSegmentation(dinst);
     670               2 :       return FALSE;
     671                 :     }
     672               2 :     if (!NCDecoderStateApplyAction(this, dinst)) return FALSE;
     673                 :     /* get ready for next round */
     674               2 :     dinst = IncrementInst(dinst);
     675               2 :   }
     676               2 :   return TRUE;
     677               2 : }
     678                 : 
     679                 : /* Default action for a decoder state pair. */
     680                 : static Bool NullNCDecoderStatePairAction(struct NCDecoderStatePair* tthis,
     681                 :                                          NCDecoderInst* old_inst,
     682               0 :                                          NCDecoderInst* new_inst) {
     683               0 :   return TRUE;
     684               0 : }
     685                 : 
     686                 : void NCDecoderStatePairConstruct(NCDecoderStatePair* tthis,
     687                 :                                  NCDecoderState* old_dstate,
     688                 :                                  NCDecoderState* new_dstate,
     689               0 :                                  NaClCopyInstructionFunc copy_func) {
     690               0 :   tthis->old_dstate = old_dstate;
     691               0 :   tthis->new_dstate = new_dstate;
     692               0 :   tthis->action_fn = NullNCDecoderStatePairAction;
     693               0 :   tthis->copy_func = copy_func;
     694               0 : }
     695                 : 
     696               0 : void NCDecoderStatePairDestruct(NCDecoderStatePair* tthis) {
     697               0 : }
     698                 : 
     699               0 : Bool NCDecoderStatePairDecode(NCDecoderStatePair* tthis) {
     700                 :   NCDecoderInst* old_dinst =
     701               0 :       &tthis->old_dstate->inst_buffer[tthis->old_dstate->cur_inst_index];
     702                 :   NCDecoderInst* new_dinst =
     703               0 :       &tthis->new_dstate->inst_buffer[tthis->new_dstate->cur_inst_index];
     704                 : 
     705                 :   /* Verify that the size of the code segments is the same, and has not
     706                 :    * been changed.
     707                 :    */
     708               0 :   if (tthis->old_dstate->size != tthis->new_dstate->size) {
     709                 :     /* If sizes differ, then they can't be the same, except for some
     710                 :      * (constant-sized) changes. Hence fail to decode.
     711                 :      */
     712               0 :     ErrorSegmentation(new_dinst);
     713               0 :     return FALSE;
     714                 :   }
     715                 : 
     716                 :   /* Since the sizes of the segments are the same, only one limit
     717                 :    * needs to be checked. Hence, we will track the limit of the new
     718                 :    * decoder state.
     719                 :    */
     720                 :   DEBUG( printf("NCDecoderStatePairDecode(%"NACL_PRIxNaClPcAddress")\n",
     721               0 :                 (NaClPcAddress) tthis->new_dstate->size));
     722                 : 
     723                 :   /* Initialize decoder statements for decoding segment, by calling
     724                 :    * the corresponding virtual in the decoder.
     725                 :    */
     726               0 :   NCDecoderStateNewSegment(tthis->old_dstate);
     727               0 :   NCDecoderStateNewSegment(tthis->new_dstate);
     728                 : 
     729                 :   /* Walk through both instruction segments, checking that
     730                 :    * they decode similarly.
     731                 :    */
     732               0 :   while (new_dinst->inst_addr < tthis->new_dstate->size) {
     733                 : 
     734               0 :     NCConsumeNextInstruction(old_dinst);
     735               0 :     NCConsumeNextInstruction(new_dinst);
     736                 : 
     737                 : 
     738                 :     /* Verify that the instruction lengths match. */
     739                 :     if (old_dinst->inst.bytes.length !=
     740               0 :         new_dinst->inst.bytes.length) {
     741               0 :       ErrorInternal(new_dinst);
     742               0 :       return FALSE;
     743                 :     }
     744                 : 
     745                 :     /* Verify that we haven't walked past the end of the segment
     746                 :      * in either decoder state.
     747                 :      *
     748                 :      * Note: Since instruction lengths are the same, and the
     749                 :      * segment lengths are the same, if overflow occurs on one
     750                 :      * segment, it must occur on the other.
     751                 :      */
     752               0 :     if (new_dinst->inst_addr > tthis->new_dstate->size) {
     753               0 :       NaClErrorReporter* reporter = new_dinst->dstate->error_reporter;
     754                 :       (*reporter->printf)(
     755                 :           reporter,
     756                 :           "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress"\n",
     757                 :           NCPrintableInstructionAddress(new_dinst),
     758               0 :           NCPrintableVLimit(tthis->new_dstate));
     759               0 :       ErrorSegmentation(new_dinst);
     760               0 :       return FALSE;
     761                 :     }
     762                 : 
     763                 :     /* Apply the action to the instructions, and continue
     764                 :      * only if the action succeeds.
     765                 :      */
     766               0 :     if (! (tthis->action_fn)(tthis, old_dinst, new_dinst)) {
     767               0 :       return FALSE;
     768                 :     }
     769                 : 
     770                 :     /* Move to next instruction. */
     771               0 :     old_dinst = IncrementInst(old_dinst);
     772               0 :     new_dinst = IncrementInst(new_dinst);
     773               0 :   }
     774               0 :   return TRUE;
     775               0 : }

Generated by: LCOV version 1.7