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: 63 53 84.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                 :  * 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             718 : 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             718 :   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             171 :       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              83 :       if (state->num_opcode_bytes == 2) {
      59                 :         uint8_t opcode_2 =
      60              83 :             state->bytes.byte[state->num_prefix_bytes + 1];
      61              83 :         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             486 :   return FALSE;
      69                 : }
      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             727 : void NaClDecodeInst(NaClInstIter* iter, NaClInstState* state) {
      80             727 :   uint8_t inst_length = 0;
      81                 :   const NaClInst* cand_insts;
      82             727 :   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             727 :   NaClInstStateInit(iter, state);
      89             727 :   if (NaClConsumePrefixBytes(state)) {
      90                 :     NaClInstPrefixDescriptor prefix_desc;
      91             727 :     Bool continue_loop = TRUE;
      92             727 :     NaClConsumeInstBytes(state, &prefix_desc);
      93             727 :     inst_length = state->bytes.length;
      94            2254 :     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             800 :       if (prefix_desc.matched_prefix == NaClInstPrefixEnumSize) {
     100               9 :         continue_loop = FALSE;
     101                 :       } else {
     102             791 :         uint8_t cur_opcode_prefix = prefix_desc.opcode_prefix;
     103             791 :         cand_insts = NaClGetNextInstCandidates(state, &prefix_desc,
     104                 :                                                &inst_length);
     105            1820 :         while (cand_insts != NULL) {
     106             956 :           NaClClearInstState(state, inst_length);
     107             956 :           state->inst = cand_insts;
     108                 :           DEBUG(NaClLog(LOG_INFO, "try opcode pattern:\n"));
     109                 :           DEBUG_OR_ERASE(NaClInstPrint(NaClLogGetGio(), state->decoder_tables,
     110                 :                                        state->inst));
     111             956 :           if (NaClConsumeAndCheckOperandSize(state) &&
     112                 :               NaClConsumeAndCheckAddressSize(state) &&
     113                 :               NaClConsumeModRm(state) &&
     114                 :               NaClConsumeSib(state) &&
     115                 :               NaClConsumeDispBytes(state) &&
     116                 :               NaClConsumeImmediateBytes(state) &&
     117                 :               NaClValidatePrefixFlags(state)) {
     118             718 :             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                 :               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                 :                             NACL_PRIx8"\n", opcode_byte));
     134               0 :               cand_inst = NaClGetPrefixOpcodeInst(state->decoder_tables,
     135                 :                                                   Prefix0F0F, opcode_byte);
     136               0 :               if (NULL != cand_inst) {
     137               0 :                 state->inst = cand_inst;
     138                 :                 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             718 :             found_match = TRUE;
     147             718 :             continue_loop = FALSE;
     148             718 :             state->num_opcode_bytes = inst_length - state->num_prefix_bytes;
     149             718 :             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             718 :             if (NaClMaybeHardCodedNop(state)) {
     158             232 :               NaClConsumeHardCodedNop(state);
     159                 :             }
     160             718 :             break;
     161                 :           } else {
     162                 :             /* match failed, try next candidate pattern. */
     163             238 :             cand_insts = NaClGetOpcodeInst(state->decoder_tables,
     164                 :                                            cand_insts->next_rule);
     165                 :           }
     166                 :         }
     167                 :         DEBUG(if (! found_match) {
     168                 :             NaClLog(LOG_INFO, "no more candidates for this prefix\n");
     169                 :           });
     170                 :       }
     171                 :     }
     172                 :   }
     173                 : 
     174             727 :   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               9 :     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                 :     DEBUG(NaClLog(LOG_INFO, "no instruction found, converting to undefined\n"));
     185               9 :     state->inst = state->decoder_tables->undefined;
     186               9 :     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                 : }
     192                 : 
     193             761 : const NaClInst* NaClInstStateInst(NaClInstState* state) {
     194             761 :   return state->inst;
     195                 : }
     196                 : 
     197             766 : NaClPcAddress NaClInstStatePrintableAddress(NaClInstState* state) {
     198             766 :   return state->iter->segment->vbase + state->inst_addr;
     199                 : }
     200                 : 
     201            2919 : NaClExpVector* NaClInstStateExpVector(NaClInstState* state) {
     202            2919 :   if (!state->nodes.is_defined) {
     203             727 :     state->nodes.is_defined = TRUE;
     204             727 :     NaClBuildExpVector(state);
     205                 :   }
     206            2919 :   return &state->nodes;
     207                 : }
     208                 : 
     209               0 : Bool NaClInstStateIsValid(NaClInstState* state) {
     210               0 :   return InstInvalid != state->inst->name;
     211                 : }
     212                 : 
     213             727 : uint8_t NaClInstStateLength(NaClInstState* state) {
     214             727 :   return state->bytes.length;
     215                 : }
     216                 : 
     217            2229 : uint8_t NaClInstStateByte(NaClInstState* state, uint8_t index) {
     218            2229 :   assert(index < state->bytes.length);
     219            2229 :   return state->bytes.byte[index];
     220                 : }
     221                 : 
     222               0 : uint8_t NaClInstStateOperandSize(NaClInstState* state) {
     223               0 :   return state->operand_size;
     224                 : }
     225                 : 
     226             407 : uint8_t NaClInstStateAddressSize(NaClInstState* state) {
     227             407 :   return state->address_size;
     228                 : }

Generated by: LCOV version 1.7