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: 92 89 96.7 %
Date: 2014-06-18 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            7721 : 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            7721 :   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            4690 :       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            1483 :       if (state->num_opcode_bytes == 2) {
      59            1279 :         uint8_t opcode_2 =
      60                 :             state->bytes.byte[state->num_prefix_bytes + 1];
      61            2568 :         if ((opcode_2 == 0x1f) || (opcode_2 == 0x0b)) return TRUE;
      62            1103 :       }
      63            1307 :       break;
      64                 :     default:
      65            3893 :       break;
      66                 :   }
      67                 :   /* If reached, can't be a (hard-coded) NOP instruction. */
      68            5200 :   return FALSE;
      69            7721 : }
      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            8475 : void NaClDecodeInst(NaClInstIter* iter, NaClInstState* state) {
      80            8475 :   uint8_t inst_length = 0;
      81            8475 :   const NaClInst* cand_insts;
      82            8475 :   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            8475 :   NaClInstStateInit(iter, state);
      89            8475 :   if (NaClConsumePrefixBytes(state)) {
      90            8475 :     NaClInstPrefixDescriptor prefix_desc;
      91            8475 :     Bool continue_loop = TRUE;
      92            8475 :     NaClConsumeInstBytes(state, &prefix_desc);
      93            8475 :     inst_length = state->bytes.length;
      94           25764 :     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            8814 :       if (prefix_desc.matched_prefix == NaClInstPrefixEnumSize) {
     100             754 :         continue_loop = FALSE;
     101             754 :       } else {
     102            8060 :         uint8_t cur_opcode_prefix = prefix_desc.opcode_prefix;
     103            8060 :         cand_insts = NaClGetNextInstCandidates(state, &prefix_desc,
     104                 :                                                &inst_length);
     105           19615 :         while (cand_insts != NULL) {
     106           11216 :           NaClClearInstState(state, inst_length);
     107           11216 :           state->inst = cand_insts;
     108           22432 :           DEBUG(NaClLog(LOG_INFO, "try opcode pattern:\n"));
     109                 :           DEBUG_OR_ERASE(NaClInstPrint(NaClLogGetGio(), state->decoder_tables,
     110                 :                                        state->inst));
     111           11216 :           if (NaClConsumeAndCheckOperandSize(state) &&
     112           10882 :               NaClConsumeAndCheckAddressSize(state) &&
     113           10868 :               NaClConsumeModRm(state) &&
     114            7723 :               NaClConsumeSib(state) &&
     115            7723 :               NaClConsumeDispBytes(state) &&
     116            7721 :               NaClConsumeImmediateBytes(state) &&
     117            7721 :               NaClValidatePrefixFlags(state)) {
     118            7795 :             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                 :                 (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              74 :               const NaClInst* cand_inst;
     130              74 :               uint8_t opcode_byte = state->bytes.byte[state->first_imm_byte];
     131             148 :               DEBUG(NaClLog(LOG_INFO,
     132                 :                             "NaClConsume immediate byte opcode char: %"
     133                 :                             NACL_PRIx8"\n", opcode_byte));
     134              74 :               cand_inst = NaClGetPrefixOpcodeInst(state->decoder_tables,
     135                 :                                                   Prefix0F0F, opcode_byte);
     136              74 :               if (NULL != cand_inst) {
     137              70 :                 state->inst = cand_inst;
     138             140 :                 DEBUG(NaClLog(LOG_INFO, "Replace with 3DNOW opcode:\n"));
     139                 :                 DEBUG_OR_ERASE(NaClInstPrint(NaClLogGetGio(),
     140                 :                                              state->decoder_tables,
     141                 :                                              state->inst));
     142              70 :               }
     143              74 :             }
     144                 : 
     145                 :             /* found a match, exit loop. */
     146            7721 :             found_match = TRUE;
     147            7721 :             continue_loop = FALSE;
     148            7721 :             state->num_opcode_bytes = inst_length - state->num_prefix_bytes;
     149            7721 :             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            7721 :             if (NaClMaybeHardCodedNop(state)) {
     158            2521 :               NaClConsumeHardCodedNop(state);
     159            2521 :             }
     160            7721 :             break;
     161                 :           } else {
     162                 :             /* match failed, try next candidate pattern. */
     163            3495 :             cand_insts = NaClGetOpcodeInst(state->decoder_tables,
     164                 :                                            cand_insts->next_rule);
     165                 :           }
     166            3495 :         }
     167           16120 :         DEBUG(if (! found_match) {
     168                 :             NaClLog(LOG_INFO, "no more candidates for this prefix\n");
     169                 :           });
     170                 :       }
     171            8814 :     }
     172            8475 :   }
     173                 : 
     174            8475 :   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             754 :     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            1508 :     DEBUG(NaClLog(LOG_INFO, "no instruction found, converting to undefined\n"));
     185             754 :     state->inst = state->decoder_tables->undefined;
     186            1454 :     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               0 :     }
     190             754 :   }
     191            8475 : }
     192                 : 
     193           10534 : const NaClInst* NaClInstStateInst(NaClInstState* state) {
     194           10534 :   return state->inst;
     195                 : }
     196                 : 
     197            4766 : NaClPcAddress NaClInstStatePrintableAddress(NaClInstState* state) {
     198            4766 :   return state->iter->segment->vbase + state->inst_addr;
     199                 : }
     200                 : 
     201           28835 : NaClExpVector* NaClInstStateExpVector(NaClInstState* state) {
     202           28835 :   if (!state->nodes.is_defined) {
     203            8475 :     state->nodes.is_defined = TRUE;
     204            8475 :     NaClBuildExpVector(state);
     205            8475 :   }
     206           28835 :   return &state->nodes;
     207                 : }
     208                 : 
     209            3368 : Bool NaClInstStateIsValid(NaClInstState* state) {
     210            3368 :   return InstInvalid != state->inst->name;
     211                 : }
     212                 : 
     213            4572 : uint8_t NaClInstStateLength(NaClInstState* state) {
     214            4572 :   return state->bytes.length;
     215                 : }
     216                 : 
     217           14407 : uint8_t NaClInstStateByte(NaClInstState* state, uint8_t index) {
     218           28814 :   assert(index < state->bytes.length);
     219           14407 :   return state->bytes.byte[index];
     220                 : }
     221                 : 
     222             157 : uint8_t NaClInstStateOperandSize(NaClInstState* state) {
     223             157 :   return state->operand_size;
     224                 : }
     225                 : 
     226            1958 : uint8_t NaClInstStateAddressSize(NaClInstState* state) {
     227            1958 :   return state->address_size;
     228                 : }

Generated by: LCOV version 1.7