LCOV - code coverage report
Current view: directory - src/trusted/validator/x86/decoder - nc_inst_state.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 81 67 82.7 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * Defines an instruction (decoder), based on the current location of
       9                 :  * the instruction iterator. The instruction decoder takes a list
      10                 :  * of candidate opcode (instruction) patterns, and searches for the
      11                 :  * first candidate that matches the requirements of the opcode pattern.
      12                 :  */
      13                 : 
      14                 : #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state.h"
      15                 : 
      16                 : /* To turn on debugging of instruction decoding, change value of
      17                 :  * DEBUGGING to 1.
      18                 :  */
      19                 : #define DEBUGGING 0
      20                 : 
      21                 : /*
      22                 :  * This .c file contains includes, static functions, and constants that are used
      23                 :  * in nc_inst_state.c, but have been factored out and put into this file, so
      24                 :  * that we can test them. That is, to allow nc_inst_state.c and
      25                 :  * nc_inst_state_Tests.cc to use them.
      26                 :  */
      27                 : #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_statics.c"
      28                 : 
      29                 : /* Returns true if the parsed instruction may be replaceable with a (hard coded)
      30                 :  * opcode sequence. Used to prefer hard-coded opcode sequences over general
      31                 :  * matches. These hard-coded opcode sequences are special nop opcode sequences,
      32                 :  * most of which are generated by compilers and linkers. The need for these
      33                 :  * hard-coded sequences is to accept nops with prefixes that would not otherwise
      34                 :  * be accepted (such as "6666666666662e0f1f840000000000").
      35                 :  */
      36               1 : static Bool NaClMaybeHardCodedNop(NaClInstState* state) {
      37                 :   /* Note: This code is based on the hard-coded instructions
      38                 :    * defined in function NaClDefNops in
      39                 :    * src/trusted/validator_x86/ncdecode_tablegen.c.
      40                 :    * If you change the hard-coded instructions defined in this
      41                 :    * function, be sure that this predicate is updated accordingly to
      42                 :    * return true for all such hard-coded instructions (it can
      43                 :    * return true on other instructions without breaking the validator).
      44                 :    */
      45                 : 
      46                 :   /* Check the first opcode byte to see if it is a special case. */
      47               1 :   switch (state->bytes.byte[state->num_prefix_bytes]) {
      48                 :     case 0x90:
      49                 :       /* If the first opcode byte is 90, it can be the NOP instruction.
      50                 :        * Return true that this can be a nop.
      51                 :        */
      52               1 :       if (state->num_opcode_bytes == 1) return TRUE;
      53               0 :       break;
      54                 :     case 0x0f:
      55                 :       /* Check that the second opcode byte is 1F or 0B. That is,
      56                 :        * can the instruction be a NOP (0f1f) or the UD2 instruction.
      57                 :        */
      58               1 :       if (state->num_opcode_bytes == 2) {
      59                 :         uint8_t opcode_2 =
      60               1 :             state->bytes.byte[state->num_prefix_bytes + 1];
      61               1 :         if ((opcode_2 == 0x1f) || (opcode_2 == 0x0b)) return TRUE;
      62                 :       }
      63                 :       break;
      64                 :     default:
      65                 :       break;
      66                 :   }
      67                 :   /* If reached, can't be a (hard-coded) NOP instruction. */
      68               1 :   return FALSE;
      69               1 : }
      70                 : 
      71                 : /* Given the current location of the (relative) pc of the given instruction
      72                 :  * iterator, update the given state to hold the (found) matched opcode
      73                 :  * (instruction) pattern. If no matching pattern exists, set the state
      74                 :  * to a matched undefined opcode (instruction) pattern. In all cases,
      75                 :  * update the state to hold all information on the matched bytes of the
      76                 :  * instruction. Note: The iterator expects that the opcode field is
      77                 :  * changed from NULL to non-NULL by this fuction.
      78                 :  */
      79               1 : void NaClDecodeInst(NaClInstIter* iter, NaClInstState* state) {
      80               1 :   uint8_t inst_length = 0;
      81                 :   const NaClInst* cand_insts;
      82               1 :   Bool found_match = FALSE;
      83                 : 
      84                 :   /* Start by consuming the prefix bytes, and getting the possible
      85                 :    * candidate opcode (instruction) patterns that can match, based
      86                 :    * on the consumed opcode bytes.
      87                 :    */
      88               1 :   NaClInstStateInit(iter, state);
      89               1 :   if (NaClConsumePrefixBytes(state)) {
      90                 :     NaClInstPrefixDescriptor prefix_desc;
      91               1 :     Bool continue_loop = TRUE;
      92               1 :     NaClConsumeInstBytes(state, &prefix_desc);
      93               1 :     inst_length = state->bytes.length;
      94               1 :     while (continue_loop) {
      95                 :       /* Try matching all possible candidates, in the order they are specified
      96                 :        * (from the most specific prefix match, to the least specific prefix
      97                 :        * match). Quit when the first pattern is matched.
      98                 :        */
      99               1 :       if (prefix_desc.matched_prefix == NaClInstPrefixEnumSize) {
     100               1 :         continue_loop = FALSE;
     101               1 :       } else {
     102               1 :         uint8_t cur_opcode_prefix = prefix_desc.opcode_prefix;
     103                 :         cand_insts = NaClGetNextInstCandidates(state, &prefix_desc,
     104               1 :                                                &inst_length);
     105               1 :         while (cand_insts != NULL) {
     106               1 :           NaClClearInstState(state, inst_length);
     107               1 :           state->inst = cand_insts;
     108               1 :           DEBUG(NaClLog(LOG_INFO, "try opcode pattern:\n"));
     109                 :           DEBUG_OR_ERASE(NaClInstPrint(NaClLogGetGio(), state->decoder_tables,
     110                 :                                        state->inst));
     111                 :           if (NaClConsumeAndCheckOperandSize(state) &&
     112                 :               NaClConsumeAndCheckAddressSize(state) &&
     113                 :               NaClConsumeModRm(state) &&
     114                 :               NaClConsumeSib(state) &&
     115                 :               NaClConsumeDispBytes(state) &&
     116                 :               NaClConsumeImmediateBytes(state) &&
     117               1 :               NaClValidatePrefixFlags(state)) {
     118                 :             if (state->inst->flags & NACL_IFLAG(Opcode0F0F) &&
     119                 :                 /* Note: If all of the above code worked correctly,
     120                 :                  * there should be no need for the following test.
     121                 :                  * However, just to be safe, it is added.
     122                 :                  */
     123               1 :                 (state->num_imm_bytes == 1)) {
     124                 :               /* Special 3DNOW instructions where opcode is in parsed
     125                 :                * immediate byte at end of instruction. Look up in table,
     126                 :                * and replace if found. Otherwise, let the default 0F0F lookup
     127                 :                * act as the matching (invalid) instruction.
     128                 :                */
     129                 :               const NaClInst* cand_inst;
     130               0 :               uint8_t opcode_byte = state->bytes.byte[state->first_imm_byte];
     131                 :               DEBUG(NaClLog(LOG_INFO,
     132                 :                             "NaClConsume immediate byte opcode char: %"
     133               0 :                             NACL_PRIx8"\n", opcode_byte));
     134                 :               cand_inst = NaClGetPrefixOpcodeInst(state->decoder_tables,
     135               0 :                                                   Prefix0F0F, opcode_byte);
     136               0 :               if (NULL != cand_inst) {
     137               0 :                 state->inst = cand_inst;
     138               0 :                 DEBUG(NaClLog(LOG_INFO, "Replace with 3DNOW opcode:\n"));
     139                 :                 DEBUG_OR_ERASE(NaClInstPrint(NaClLogGetGio(),
     140                 :                                              state->decoder_tables,
     141                 :                                              state->inst));
     142                 :               }
     143                 :             }
     144                 : 
     145                 :             /* found a match, exit loop. */
     146               1 :             found_match = TRUE;
     147               1 :             continue_loop = FALSE;
     148               1 :             state->num_opcode_bytes = inst_length - state->num_prefix_bytes;
     149               1 :             state->opcode_prefix = cur_opcode_prefix;
     150                 : 
     151                 :             /* If an instruction has both a general form, and a (hard-coded)
     152                 :              * explicit opcode sequence, prefer the latter for the match.
     153                 :              * Note: This selection to the (hard-coded) explicit opcode
     154                 :              * sequence is necessary if we are to handle special nops with
     155                 :              * multiple prefix bytes in the x86-64 validator.
     156                 :              */
     157               1 :             if (NaClMaybeHardCodedNop(state)) {
     158               1 :               NaClConsumeHardCodedNop(state);
     159                 :             }
     160               1 :             break;
     161                 :           } else {
     162                 :             /* match failed, try next candidate pattern. */
     163                 :             cand_insts = NaClGetOpcodeInst(state->decoder_tables,
     164               1 :                                            cand_insts->next_rule);
     165                 :           }
     166               1 :         }
     167                 :         DEBUG(if (! found_match) {
     168                 :             NaClLog(LOG_INFO, "no more candidates for this prefix\n");
     169               1 :           });
     170                 :       }
     171               1 :     }
     172                 :   }
     173                 : 
     174               1 :   if (!found_match) {
     175                 :     /* No instruction matched. Double check that it can't be a hard-coded
     176                 :      * NOP instruction before we assume that we can't can accept the
     177                 :      * instruction.
     178                 :      */
     179               1 :     if (NaClConsumeHardCodedNop(state)) return;
     180                 : 
     181                 :     /* We did not match a defined opcode, match the undefined opcode,
     182                 :      * forcing the inst field to be non-NULL, and to read at least one byte.
     183                 :      */
     184               1 :     DEBUG(NaClLog(LOG_INFO, "no instruction found, converting to undefined\n"));
     185               1 :     state->inst = state->decoder_tables->undefined;
     186               1 :     if (state->bytes.length == 0 && state->bytes.length < state->length_limit) {
     187                 :       /* Make sure we eat at least one byte. */
     188               0 :       NCInstBytesReadInline(&state->bytes);
     189                 :     }
     190                 :   }
     191               1 : }
     192                 : 
     193               1 : const NaClInst* NaClInstStateInst(NaClInstState* state) {
     194               1 :   return state->inst;
     195               1 : }
     196                 : 
     197               1 : NaClPcAddress NaClInstStatePrintableAddress(NaClInstState* state) {
     198               1 :   return state->iter->segment->vbase + state->inst_addr;
     199               1 : }
     200                 : 
     201               1 : NaClExpVector* NaClInstStateExpVector(NaClInstState* state) {
     202               1 :   if (!state->nodes.is_defined) {
     203               1 :     state->nodes.is_defined = TRUE;
     204               1 :     NaClBuildExpVector(state);
     205                 :   }
     206               1 :   return &state->nodes;
     207               1 : }
     208                 : 
     209               0 : Bool NaClInstStateIsValid(NaClInstState* state) {
     210               0 :   return InstInvalid != state->inst->name;
     211               0 : }
     212                 : 
     213               1 : uint8_t NaClInstStateLength(NaClInstState* state) {
     214               1 :   return state->bytes.length;
     215               1 : }
     216                 : 
     217               1 : uint8_t NaClInstStateByte(NaClInstState* state, uint8_t index) {
     218               1 :   assert(index < state->bytes.length);
     219               1 :   return state->bytes.byte[index];
     220               1 : }
     221                 : 
     222               0 : uint8_t NaClInstStateOperandSize(NaClInstState* state) {
     223               0 :   return state->operand_size;
     224               0 : }
     225                 : 
     226               1 : uint8_t NaClInstStateAddressSize(NaClInstState* state) {
     227               1 :   return state->address_size;
     228               1 : }

Generated by: LCOV version 1.7