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

Generated by: LCOV version 1.7