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: 354 279 78.8 %
Date: 2014-07-02 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                 : }
      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                 : }
     101             215 : static void NullDecoderMethod(struct NCDecoderState* dstate) {
     102                 :   UNREFERENCED_PARAMETER(dstate);
     103             215 : }
     104                 : 
     105                 : /* API to virtual methods of a decoder state. */
     106             396 : void NCDecoderStateNewSegment(NCDecoderState* tthis) {
     107             396 :   (tthis->new_segment_fn)(tthis);
     108             396 : }
     109                 : 
     110          482375 : static Bool NCDecoderStateApplyAction(NCDecoderState* tthis,
     111                 :                                       NCDecoderInst* dinst) {
     112          482375 :   return (tthis->action_fn)(dinst);
     113                 : }
     114                 : 
     115              10 : static void NCDecoderStateSegmentationError(NCDecoderState* tthis) {
     116              10 :   (tthis->segmentation_error_fn)(tthis);
     117              10 : }
     118                 : 
     119               0 : static void NCDecoderStateInternalError(NCDecoderState* tthis) {
     120               0 :   (tthis->internal_error_fn)(tthis);
     121               0 : }
     122                 : 
     123                 : /* Error Condition Handling */
     124              10 : static void ErrorSegmentation(NCDecoderInst* dinst) {
     125              10 :   NCDecoderState* dstate = dinst->dstate;
     126              10 :   NaClErrorReporter* reporter = dstate->error_reporter;
     127              10 :   (*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              10 :   NCDecoderStateSegmentationError(dstate);
     132              10 : }
     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              10 : static void NCRemainingMemoryInternalError(NCRemainingMemoryError error,
     146                 :                                            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              10 :   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              10 : }
     157                 : 
     158          482441 : static INLINE void InitDecoder(struct NCDecoderInst* dinst) {
     159          482441 :   NCInstBytesInitInline(&dinst->inst.bytes);
     160          482441 :   dinst->inst.prefixbytes = 0;
     161          482441 :   dinst->inst.prefixmask = 0;
     162          482441 :   dinst->inst.opcode_prefixmask = 0;
     163          482441 :   dinst->inst.num_opbytes = 1;  /* unless proven otherwise. */
     164          482441 :   dinst->inst.hassibbyte = 0;
     165          482441 :   dinst->inst.mrm = 0;
     166          482441 :   dinst->inst.immtype = IMM_UNKNOWN;
     167          482441 :   dinst->inst.immbytes = 0;
     168          482441 :   dinst->inst.dispbytes = 0;
     169          482441 :   dinst->inst.rexprefix = 0;
     170          482441 :   dinst->inst.lock_prefix_index = kNoLockPrefixIndex;
     171          482441 :   dinst->opinfo = NULL;
     172          482441 : }
     173                 : 
     174                 : /* Returns the number of bytes defined for the operand of the instruction. */
     175            2510 : static int ExtractOperandSize(NCDecoderInst* dinst) {
     176                 :   if (NACL_TARGET_SUBARCH == 64 &&
     177                 :       dinst->inst.rexprefix && dinst->inst.rexprefix & 0x8) {
     178                 :     return 8;
     179                 :   }
     180            2510 :   if (dinst->inst.prefixmask & kPrefixDATA16) {
     181              29 :     return 2;
     182                 :   }
     183            2481 :   return 4;
     184                 : }
     185                 : 
     186                 : /* at most four prefix bytes are allowed */
     187          482385 : static void ConsumePrefixBytes(struct NCDecoderInst* dinst) {
     188                 :   uint8_t nb;
     189                 :   int ii;
     190                 :   uint32_t prefix_form;
     191                 : 
     192          486494 :   for (ii = 0; ii < kMaxPrefixBytes; ++ii) {
     193          486458 :     nb = NCRemainingMemoryGetNext(&dinst->dstate->memory);
     194          486458 :     prefix_form = kPrefixTable[nb];
     195          486458 :     if (prefix_form == 0) return;
     196                 :     DEBUG( printf("Consume prefix[%d]: %02x => %x\n", ii, nb, prefix_form) );
     197            4109 :     dinst->inst.prefixmask |= prefix_form;
     198            4109 :     dinst->inst.prefixmask |= kPrefixTable[nb];
     199            4109 :     dinst->inst.prefixbytes += 1;
     200            4109 :     NCInstBytesReadInline(&dinst->inst.bytes);
     201                 :     DEBUG( printf("  prefix mask: %08x\n", dinst->inst.prefixmask) );
     202                 :     if (NACL_TARGET_SUBARCH == 64 && prefix_form == kPrefixREX) {
     203                 :       dinst->inst.rexprefix = nb;
     204                 :       /* REX prefix must be last prefix. */
     205                 :       return;
     206                 :     }
     207            4109 :     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              41 :       dinst->inst.lock_prefix_index = (uint8_t) ii;
     213                 :     }
     214                 :   }
     215                 : }
     216                 : 
     217           10265 : static const struct OpInfo* GetExtendedOpInfo(NCDecoderInst* dinst,
     218                 :                                               uint8_t opbyte2) {
     219                 :   uint32_t pm;
     220           10265 :   pm = dinst->inst.prefixmask;
     221           10265 :   if ((pm & (kPrefixDATA16 | kPrefixREPNE | kPrefixREP)) == 0) {
     222            8918 :     return &kDecode0FXXOp[opbyte2];
     223            1347 :   } else if (pm & kPrefixDATA16) {
     224             305 :     dinst->inst.prefixmask &= ~kPrefixDATA16;
     225             305 :     dinst->inst.opcode_prefixmask = kPrefixDATA16;
     226             305 :     return &kDecode660FXXOp[opbyte2];
     227            1042 :   } else if (pm & kPrefixREPNE) {
     228            1028 :     dinst->inst.prefixmask &= ~kPrefixREPNE;
     229            1028 :     dinst->inst.opcode_prefixmask = kPrefixREPNE;
     230            1028 :     return &kDecodeF20FXXOp[opbyte2];
     231              14 :   } else if (pm & kPrefixREP) {
     232              14 :     dinst->inst.prefixmask &= ~kPrefixREP;
     233              14 :     dinst->inst.opcode_prefixmask = kPrefixREP;
     234              14 :     return &kDecodeF30FXXOp[opbyte2];
     235                 :   }
     236               0 :   ErrorInternal(dinst);
     237               0 :   return dinst->opinfo;
     238                 : }
     239                 : 
     240             439 : static void GetX87OpInfo(NCDecoderInst* dinst) {
     241                 :   /* WAIT is an x87 instruction but not in the coproc opcode space. */
     242             439 :   uint8_t op1 = NCInstBytesByteInline(&dinst->inst_bytes,
     243             439 :                                       dinst->inst.prefixbytes);
     244             439 :   if (op1 < kFirstX87Opcode || op1 > kLastX87Opcode) {
     245               0 :     if (op1 != kWAITOp) ErrorInternal(dinst);
     246             439 :     return;
     247                 :   }
     248             439 :   dinst->opinfo = &kDecodeX87Op[op1 - kFirstX87Opcode][dinst->inst.mrm];
     249                 :   DEBUG( printf("NACL_X87 op1 = %02x, ", op1);
     250                 :          PrintOpInfo(dinst->opinfo) );
     251                 : }
     252                 : 
     253          482385 : static void ConsumeOpcodeBytes(NCDecoderInst* dinst) {
     254          482385 :   uint8_t opcode = NCInstBytesReadInline(&dinst->inst.bytes);
     255          482385 :   dinst->opinfo = &kDecode1ByteOp[opcode];
     256                 :   DEBUG( printf("NACLi_1BYTE: opcode = %02x, ", opcode);
     257                 :          PrintOpInfo(dinst->opinfo) );
     258          482385 :   if (opcode == kTwoByteOpcodeByte1) {
     259           10265 :     uint8_t opcode2 = NCInstBytesReadInline(&dinst->inst.bytes);
     260           10265 :     dinst->opinfo = GetExtendedOpInfo(dinst, opcode2);
     261                 :     DEBUG( printf("NACLi_2BYTE: opcode2 = %02x, ", opcode2);
     262                 :            PrintOpInfo(dinst->opinfo) );
     263           10265 :     dinst->inst.num_opbytes = 2;
     264           10265 :     if (dinst->opinfo->insttype == NACLi_3BYTE) {
     265              19 :       uint8_t opcode3 = NCInstBytesReadInline(&dinst->inst.bytes);
     266                 :       uint32_t pm;
     267              19 :       pm = dinst->inst.opcode_prefixmask;
     268              19 :       dinst->inst.num_opbytes = 3;
     269                 : 
     270                 :       DEBUG( printf("NACLi_3BYTE: opcode3 = %02x, ", opcode3) );
     271              19 :       switch (opcode2) {
     272                 :       case 0x38:        /* SSSE3, SSE4 */
     273               9 :         if (pm & kPrefixDATA16) {
     274               5 :           dinst->opinfo = &kDecode660F38Op[opcode3];
     275               4 :         } else if (pm & kPrefixREPNE) {
     276               4 :           dinst->opinfo = &kDecodeF20F38Op[opcode3];
     277               0 :         } else if (pm == 0) {
     278               0 :           dinst->opinfo = &kDecode0F38Op[opcode3];
     279                 :         } 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               9 :         break;
     286                 :       case 0x3A:        /* SSSE3, SSE4 */
     287              10 :         if (pm & kPrefixDATA16) {
     288               8 :           dinst->opinfo = &kDecode660F3AOp[opcode3];
     289               2 :         } else if (pm == 0) {
     290               2 :           dinst->opinfo = &kDecode0F3AOp[opcode3];
     291                 :         } 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              10 :         break;
     298                 :       default:
     299                 :         /* if this happens there is a decoding table bug */
     300               0 :         ErrorInternal(dinst);
     301               0 :         break;
     302                 :       }
     303                 :       DEBUG( PrintOpInfo(dinst->opinfo) );
     304                 :     }
     305                 :   }
     306          482385 :   dinst->inst.immtype = dinst->opinfo->immtype;
     307          482385 : }
     308                 : 
     309          482385 : static void ConsumeModRM(NCDecoderInst* dinst) {
     310          482385 :   if (dinst->opinfo->hasmrmbyte != 0) {
     311          103949 :     const uint8_t mrm = NCInstBytesReadInline(&dinst->inst.bytes);
     312                 :     DEBUG( printf("Mod/RM byte: %02x\n", mrm) );
     313          103949 :     dinst->inst.mrm = mrm;
     314          207459 :     if (dinst->opinfo->insttype == NACLi_X87 ||
     315          103510 :         dinst->opinfo->insttype == NACLi_X87_FSINCOS) {
     316             439 :       GetX87OpInfo(dinst);
     317                 :     }
     318          103949 :     if (dinst->opinfo->opinmrm) {
     319           30587 :       const struct OpInfo* mopinfo =
     320           30587 :         &kDecodeModRMOp[dinst->opinfo->opinmrm][modrm_opcodeInline(mrm)];
     321           30587 :       dinst->opinfo = mopinfo;
     322                 :       DEBUG( printf("NACLi_opinmrm: modrm.opcode = %x, ",
     323                 :                     modrm_opcodeInline(mrm));
     324                 :              PrintOpInfo(dinst->opinfo) );
     325           30587 :       if (dinst->inst.immtype == IMM_UNKNOWN) {
     326               0 :         assert(0);
     327                 :         dinst->inst.immtype = mopinfo->immtype;
     328                 :       }
     329                 :       /* handle weird case for 0xff TEST Ib/Iv */
     330           30587 :       if (modrm_opcodeInline(mrm) == 0) {
     331           13788 :         if (dinst->inst.immtype == IMM_GROUP3_F6) {
     332             932 :           dinst->inst.immtype = IMM_FIXED1;
     333                 :         }
     334           13788 :         if (dinst->inst.immtype == IMM_GROUP3_F7) {
     335             137 :           dinst->inst.immtype = IMM_DATAV;
     336                 :         }
     337                 :       }
     338                 :       DEBUG( printf("  immtype = %s\n",
     339                 :                     NCDecodeImmediateTypeName(dinst->inst.immtype)) );
     340                 :     }
     341          103949 :     if (dinst->inst.prefixmask & kPrefixADDR16) {
     342              19 :       switch (modrm_modInline(mrm)) {
     343                 :         case 0:
     344               9 :           if (modrm_rmInline(mrm) == 0x06) {
     345               0 :             dinst->inst.dispbytes = 2;        /* disp16 */
     346                 :           } else {
     347               9 :             dinst->inst.dispbytes = 0;
     348                 :           }
     349               9 :           break;
     350                 :         case 1:
     351               4 :           dinst->inst.dispbytes = 1;           /* disp8 */
     352               4 :           break;
     353                 :         case 2:
     354               4 :           dinst->inst.dispbytes = 2;           /* disp16 */
     355               4 :           break;
     356                 :         case 3:
     357               2 :           dinst->inst.dispbytes = 0;           /* no disp */
     358               2 :           break;
     359                 :         default:
     360               0 :           ErrorInternal(dinst);
     361                 :       }
     362              19 :       dinst->inst.hassibbyte = 0;
     363                 :     } else {
     364          103930 :       switch (modrm_modInline(mrm)) {
     365                 :         case 0:
     366           10139 :           if (modrm_rmInline(mrm) == 0x05) {
     367            1281 :             dinst->inst.dispbytes = 4;         /* disp32 */
     368                 :           } else {
     369            8858 :             dinst->inst.dispbytes = 0;
     370                 :           }
     371           10139 :           break;
     372                 :         case 1:
     373           39720 :           dinst->inst.dispbytes = 1;           /* disp8 */
     374           39720 :           break;
     375                 :         case 2:
     376           15341 :           dinst->inst.dispbytes = 4;           /* disp32 */
     377           15341 :           break;
     378                 :         case 3:
     379           38730 :           dinst->inst.dispbytes = 0;           /* no disp */
     380           38730 :           break;
     381                 :         default:
     382               0 :           ErrorInternal(dinst);
     383                 :       }
     384          127951 :       dinst->inst.hassibbyte = ((modrm_rmInline(mrm) == 0x04) &&
     385           24021 :                                  (modrm_modInline(mrm) != 3));
     386                 :     }
     387                 :   }
     388                 :   DEBUG( printf("  dispbytes = %d, hasibbyte = %d\n",
     389                 :                 dinst->inst.dispbytes, dinst->inst.hassibbyte) );
     390          482385 : }
     391                 : 
     392          482385 : static INLINE void ConsumeSIB(NCDecoderInst* dinst) {
     393          482385 :   if (dinst->inst.hassibbyte != 0) {
     394           17805 :     const uint8_t sib = NCInstBytesReadInline(&dinst->inst.bytes);
     395           17805 :     if (sib_base(sib) == 0x05) {
     396             609 :       switch (modrm_modInline(dinst->inst.mrm)) {
     397             561 :       case 0: dinst->inst.dispbytes = 4; break;
     398              47 :       case 1: dinst->inst.dispbytes = 1; break;
     399               1 :       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                 :                   sib, dinst->inst.dispbytes) );
     407                 :   }
     408          482385 : }
     409                 : 
     410          482385 : static INLINE void ConsumeID(NCDecoderInst* dinst) {
     411          482385 :   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          482385 :   if (dinst->inst.immtype == IMM_MOV_DATAV) {
     416            2510 :     dinst->inst.immbytes = ExtractOperandSize(dinst);
     417          479875 :   } else if (dinst->inst.prefixmask & kPrefixDATA16) {
     418            2026 :     dinst->inst.immbytes = kImmTypeToSize66[dinst->inst.immtype];
     419          477849 :   } else if (dinst->inst.prefixmask & kPrefixADDR16) {
     420              17 :     dinst->inst.immbytes = kImmTypeToSize67[dinst->inst.immtype];
     421                 :   } else {
     422          477832 :     dinst->inst.immbytes = kImmTypeToSize[dinst->inst.immtype];
     423                 :   }
     424          482385 :   NCInstBytesReadBytesInline((ssize_t) dinst->inst.immbytes,
     425                 :                              &dinst->inst.bytes);
     426          482385 :   NCInstBytesReadBytesInline((ssize_t) dinst->inst.dispbytes,
     427                 :                              &dinst->inst.bytes);
     428                 :   DEBUG(printf("ID: %d disp bytes, %d imm bytes\n",
     429                 :                dinst->inst.dispbytes, dinst->inst.immbytes));
     430          482385 : }
     431                 : 
     432                 : /* Actually this routine is special for 3DNow instructions */
     433          482385 : static INLINE void MaybeGet3ByteOpInfo(NCDecoderInst* dinst) {
     434          482385 :   if (dinst->opinfo->insttype == NACLi_3DNOW) {
     435               9 :     uint8_t opbyte1 = NCInstBytesByteInline(&dinst->inst_bytes,
     436               9 :                                       dinst->inst.prefixbytes);
     437               9 :     uint8_t opbyte2 = NCInstBytesByteInline(&dinst->inst_bytes,
     438               9 :                                       dinst->inst.prefixbytes + 1);
     439              18 :     if (opbyte1 == kTwoByteOpcodeByte1 &&
     440               9 :         opbyte2 == k3DNowOpcodeByte2) {
     441               8 :       uint8_t immbyte =
     442               8 :           NCInstBytesByteInline(&dinst->inst_bytes,
     443               8 :                                 dinst->inst.bytes.length - 1);
     444               8 :       dinst->opinfo = &kDecode0F0FOp[immbyte];
     445                 :       DEBUG( printf(
     446                 :                  "NACLi_3DNOW: byte1 = %02x, byte2 = %02x, immbyte = %02x,\n  ",
     447                 :                  opbyte1, opbyte2, immbyte);
     448                 :              PrintOpInfo(dinst->opinfo) );
     449                 :     }
     450                 :   }
     451          482385 : }
     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          483353 : static NCDecoderInst* NCGetInstDiff(const NCDecoderInst* dinst,
     458                 :                                       int nindex) {
     459                 :   /* Note: This code also handles increments, so that we can
     460                 :    * use the same code for both.
     461                 :    */
     462          483353 :   size_t index = (dinst->inst_index + nindex) % dinst->dstate->inst_buffer_size;
     463          483353 :   return &dinst->dstate->inst_buffer[index];
     464                 : }
     465                 : 
     466             983 : struct NCDecoderInst* PreviousInst(const NCDecoderInst* dinst,
     467                 :                                    int nindex) {
     468             983 :   if ((nindex > 0) && (((size_t) nindex) < dinst->inst_count)) {
     469             978 :     return NCGetInstDiff(dinst, -nindex);
     470                 :   } else {
     471               5 :     return NULL;
     472                 :   }
     473                 : }
     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             396 : static void NCDecoderStateInitFields(NCDecoderState* this) {
     480                 :   size_t dbindex;
     481             396 :   this->error_reporter = &kNCNullErrorReporter;
     482             396 :   NCRemainingMemoryInit(this->mbase, this->size, &this->memory);
     483             396 :   this->memory.error_fn = NCRemainingMemoryInternalError;
     484             396 :   this->memory.error_fn_state = (void*) this;
     485            1344 :   for (dbindex = 0; dbindex < this->inst_buffer_size; ++dbindex) {
     486             948 :     this->inst_buffer[dbindex].dstate = this;
     487             948 :     this->inst_buffer[dbindex].inst_index = dbindex;
     488             948 :     this->inst_buffer[dbindex].inst_count = 1;
     489             948 :     this->inst_buffer[dbindex].inst_addr = 0;
     490             948 :     this->inst_buffer[dbindex].unchanged = FALSE;
     491             948 :     NCInstBytesInitMemory(&this->inst_buffer[dbindex].inst.bytes,
     492                 :                           &this->memory);
     493             948 :     NCInstBytesPtrInit((NCInstBytesPtr*) &this->inst_buffer[dbindex].inst_bytes,
     494             948 :                        &this->inst_buffer[dbindex].inst.bytes);
     495                 :   }
     496             396 :   this->cur_inst_index = 0;
     497             396 : }
     498                 : 
     499             396 : void NCDecoderStateConstruct(NCDecoderState* this,
     500                 :                              uint8_t* mbase, NaClPcAddress vbase,
     501                 :                              NaClMemorySize size,
     502                 :                              NCDecoderInst* inst_buffer,
     503                 :                              size_t inst_buffer_size) {
     504                 : 
     505                 :   /* Start by setting up virtual functions. */
     506             396 :   this->action_fn = NullDecoderAction;
     507             396 :   this->new_segment_fn = NullDecoderMethod;
     508             396 :   this->segmentation_error_fn = NullDecoderMethod;
     509             396 :   this->internal_error_fn = NullDecoderMethod;
     510                 : 
     511                 :   /* Initialize the user-provided fields. */
     512             396 :   this->mbase = mbase;
     513             396 :   this->vbase = vbase;
     514             396 :   this->size = size;
     515             396 :   this->inst_buffer = inst_buffer;
     516             396 :   this->inst_buffer_size = inst_buffer_size;
     517                 : 
     518             396 :   NCDecoderStateInitFields(this);
     519             396 : }
     520                 : 
     521             386 : void NCDecoderStateDestruct(NCDecoderState* this) {
     522                 :   /* Currently, there is nothing to do. */
     523             386 : }
     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              10 : static INLINE NaClPcAddress NCPrintableVLimit(NCDecoderState *dstate) {
     532              10 :   return dstate->vbase + dstate->size;
     533                 : }
     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          482375 : 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          482375 :   NCDecoderInst* next_inst = NCGetInstDiff(inst, 1);
     543          482375 :   next_inst->inst_addr = inst->inst_addr + inst->inst.bytes.length;
     544          482375 :   next_inst->dstate->cur_inst_index = next_inst->inst_index;
     545          482375 :   next_inst->inst_count = inst->inst_count + 1;
     546          482375 :   next_inst->unchanged = FALSE;
     547          482375 :   return next_inst;
     548                 : }
     549                 : 
     550                 : /* Get the i-th byte of the current instruction being parsed. */
     551             870 : static uint8_t GetInstByte(NCDecoderInst* dinst, ssize_t i) {
     552             870 :   if (i < dinst->inst.bytes.length) {
     553             420 :     return dinst->inst.bytes.byte[i];
     554                 :   } else {
     555             450 :     return NCRemainingMemoryLookaheadInline(&dinst->dstate->memory,
     556             450 :                                             i - dinst->inst.bytes.length);
     557                 :   }
     558                 : }
     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             186 : static void ConsumePredefinedNop(NCDecoderInst* dinst) {
     565                 :   /* Do maximal match of possible nops */
     566             186 :   uint8_t pos = 0;
     567             186 :   struct OpInfo* matching_opinfo = NULL;
     568             186 :   ssize_t matching_length = 0;
     569             186 :   NCNopTrieNode* next = (NCNopTrieNode*) (kNcNopTrieNode + 0);
     570             186 :   uint8_t byte = GetInstByte(dinst, pos);
     571            1361 :   while (NULL != next) {
     572             989 :     if (byte == next->matching_byte) {
     573                 :       DEBUG(printf("NOP match byte: 0x%02x\n", (int) byte));
     574             684 :       byte = GetInstByte(dinst, ++pos);
     575             684 :       if (NULL != next->matching_opinfo) {
     576                 :         DEBUG(printf("NOP matched rule! %d\n", pos));
     577              56 :         matching_opinfo = next->matching_opinfo;
     578              56 :         matching_length = pos;
     579                 :       }
     580             684 :       next = next->success;
     581                 :     } else {
     582             305 :       next = next->fail;
     583                 :     }
     584                 :   }
     585             186 :   if (NULL == matching_opinfo) {
     586                 :     DEBUG(printf("NOP match failed!\n"));
     587                 :   } else {
     588                 :     DEBUG(printf("NOP match succeeds! Using last matched rule.\n"));
     589              56 :     NCRemainingMemoryResetInline(&dinst->dstate->memory);
     590              56 :     InitDecoder(dinst);
     591              56 :     NCInstBytesReadBytesInline(matching_length, &dinst->inst.bytes);
     592              56 :     dinst->opinfo = matching_opinfo;
     593                 :   }
     594             186 : }
     595                 : 
     596                 : /* If we didn't find a good instruction, try to consume one of the
     597                 :  * predefined NOP's.
     598                 :  */
     599          482385 : static void MaybeConsumePredefinedNop(NCDecoderInst* dinst) {
     600          482385 :   switch (dinst->opinfo->insttype) {
     601                 :     case NACLi_UNDEFINED:
     602                 :     case NACLi_INVALID:
     603                 :     case NACLi_ILLEGAL:
     604             186 :       ConsumePredefinedNop(dinst);
     605             186 :       break;
     606                 :     default:
     607          482199 :       break;
     608                 :   }
     609          482385 : }
     610                 : 
     611                 : /* All of the actions needed to read one additional instruction into mstate.
     612                 :  */
     613          482385 : void NCConsumeNextInstruction(struct NCDecoderInst* inst) {
     614                 :   DEBUG( printf("Decoding instruction at %"NACL_PRIxNaClPcAddress":\n",
     615                 :                 inst->inst_addr) );
     616          482385 :   InitDecoder(inst);
     617          482385 :   ConsumePrefixBytes(inst);
     618          482385 :   ConsumeOpcodeBytes(inst);
     619          482385 :   ConsumeModRM(inst);
     620          482385 :   ConsumeSIB(inst);
     621          482385 :   ConsumeID(inst);
     622          482385 :   MaybeGet3ByteOpInfo(inst);
     623          482385 :   MaybeConsumePredefinedNop(inst);
     624          482385 : }
     625                 : 
     626             570 : void NCDecoderStateSetErrorReporter(NCDecoderState* this,
     627                 :                                     NaClErrorReporter* reporter) {
     628             570 :   switch (reporter->supported_reporter) {
     629                 :     case NaClNullErrorReporter:
     630                 :     case NCDecoderInstErrorReporter:
     631             570 :       this->error_reporter = reporter;
     632             570 :       return;
     633                 :     default:
     634               0 :       break;
     635                 :   }
     636               0 :   (*reporter->printf)(
     637                 :       reporter,
     638                 :       "*** FATAL: using unsupported error reporter! ***\n"
     639                 :       "*** NCDecoderInstErrorReporter expected but found %s***\n",
     640                 :       NaClErrorReporterSupportedName(reporter->supported_reporter));
     641               0 :   exit(1);
     642                 : }
     643                 : 
     644               0 : 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             396 : Bool NCDecoderStateDecode(NCDecoderState* this) {
     655             396 :   NCDecoderInst* dinst = &this->inst_buffer[this->cur_inst_index];
     656                 :   DEBUG( printf("DecodeSegment(%p[%"NACL_PRIxNaClPcAddress"])\n",
     657                 :                 (void*) this->memory.mpc, (NaClPcAddress) this->size) );
     658             396 :   NCDecoderStateNewSegment(this);
     659          483167 :   while (dinst->inst_addr < this->size) {
     660          482385 :     NCConsumeNextInstruction(dinst);
     661          482385 :     if (this->memory.overflow_count) {
     662              20 :       NaClPcAddress newpc = (NCPrintableInstructionAddress(dinst)
     663              10 :                              + dinst->inst.bytes.length);
     664              30 :       (*this->error_reporter->printf)(
     665              10 :           this->error_reporter,
     666                 :           "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress
     667                 :           " (read overflow of %d bytes)\n",
     668              10 :           newpc, NCPrintableVLimit(this), this->memory.overflow_count);
     669              10 :       ErrorSegmentation(dinst);
     670              10 :       return FALSE;
     671                 :     }
     672          482375 :     if (!NCDecoderStateApplyAction(this, dinst)) return FALSE;
     673                 :     /* get ready for next round */
     674          482375 :     dinst = IncrementInst(dinst);
     675                 :   }
     676             386 :   return TRUE;
     677                 : }
     678                 : 
     679                 : /* Default action for a decoder state pair. */
     680               0 : static Bool NullNCDecoderStatePairAction(struct NCDecoderStatePair* tthis,
     681                 :                                          NCDecoderInst* old_inst,
     682                 :                                          NCDecoderInst* new_inst) {
     683               0 :   return TRUE;
     684                 : }
     685                 : 
     686               0 : void NCDecoderStatePairConstruct(NCDecoderStatePair* tthis,
     687                 :                                  NCDecoderState* old_dstate,
     688                 :                                  NCDecoderState* new_dstate,
     689                 :                                  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               0 :   NCDecoderInst* old_dinst =
     701               0 :       &tthis->old_dstate->inst_buffer[tthis->old_dstate->cur_inst_index];
     702               0 :   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                 :                 (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               0 :     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               0 :       (*reporter->printf)(
     755                 :           reporter,
     756                 :           "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress"\n",
     757                 :           NCPrintableInstructionAddress(new_dinst),
     758                 :           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                 :   }
     774               0 :   return TRUE;
     775                 : }

Generated by: LCOV version 1.7