| OLD | NEW |
| (Empty) |
| 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 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 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 if (state->num_opcode_bytes == 1) return TRUE; | |
| 53 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 if (state->num_opcode_bytes == 2) { | |
| 59 uint8_t opcode_2 = | |
| 60 state->bytes.byte[state->num_prefix_bytes + 1]; | |
| 61 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 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 void NaClDecodeInst(NaClInstIter* iter, NaClInstState* state) { | |
| 80 uint8_t inst_length = 0; | |
| 81 const NaClInst* cand_insts; | |
| 82 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 NaClInstStateInit(iter, state); | |
| 89 if (NaClConsumePrefixBytes(state)) { | |
| 90 NaClInstPrefixDescriptor prefix_desc; | |
| 91 Bool continue_loop = TRUE; | |
| 92 NaClConsumeInstBytes(state, &prefix_desc); | |
| 93 inst_length = state->bytes.length; | |
| 94 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 if (prefix_desc.matched_prefix == NaClInstPrefixEnumSize) { | |
| 100 continue_loop = FALSE; | |
| 101 } else { | |
| 102 uint8_t cur_opcode_prefix = prefix_desc.opcode_prefix; | |
| 103 cand_insts = NaClGetNextInstCandidates(state, &prefix_desc, | |
| 104 &inst_length); | |
| 105 while (cand_insts != NULL) { | |
| 106 NaClClearInstState(state, inst_length); | |
| 107 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 if (NaClConsumeAndCheckOperandSize(state) && | |
| 112 NaClConsumeAndCheckAddressSize(state) && | |
| 113 NaClConsumeModRm(state) && | |
| 114 NaClConsumeSib(state) && | |
| 115 NaClConsumeDispBytes(state) && | |
| 116 NaClConsumeImmediateBytes(state) && | |
| 117 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 (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 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 cand_inst = NaClGetPrefixOpcodeInst(state->decoder_tables, | |
| 135 Prefix0F0F, opcode_byte); | |
| 136 if (NULL != cand_inst) { | |
| 137 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 found_match = TRUE; | |
| 147 continue_loop = FALSE; | |
| 148 state->num_opcode_bytes = inst_length - state->num_prefix_bytes; | |
| 149 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 if (NaClMaybeHardCodedNop(state)) { | |
| 158 NaClConsumeHardCodedNop(state); | |
| 159 } | |
| 160 break; | |
| 161 } else { | |
| 162 /* match failed, try next candidate pattern. */ | |
| 163 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 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 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 state->inst = state->decoder_tables->undefined; | |
| 186 if (state->bytes.length == 0 && state->bytes.length < state->length_limit) { | |
| 187 /* Make sure we eat at least one byte. */ | |
| 188 NCInstBytesReadInline(&state->bytes); | |
| 189 } | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 const NaClInst* NaClInstStateInst(NaClInstState* state) { | |
| 194 return state->inst; | |
| 195 } | |
| 196 | |
| 197 NaClPcAddress NaClInstStatePrintableAddress(NaClInstState* state) { | |
| 198 return state->iter->segment->vbase + state->inst_addr; | |
| 199 } | |
| 200 | |
| 201 NaClExpVector* NaClInstStateExpVector(NaClInstState* state) { | |
| 202 if (!state->nodes.is_defined) { | |
| 203 state->nodes.is_defined = TRUE; | |
| 204 NaClBuildExpVector(state); | |
| 205 } | |
| 206 return &state->nodes; | |
| 207 } | |
| 208 | |
| 209 Bool NaClInstStateIsValid(NaClInstState* state) { | |
| 210 return InstInvalid != state->inst->name; | |
| 211 } | |
| 212 | |
| 213 uint8_t NaClInstStateLength(NaClInstState* state) { | |
| 214 return state->bytes.length; | |
| 215 } | |
| 216 | |
| 217 uint8_t NaClInstStateByte(NaClInstState* state, uint8_t index) { | |
| 218 assert(index < state->bytes.length); | |
| 219 return state->bytes.byte[index]; | |
| 220 } | |
| 221 | |
| 222 uint8_t NaClInstStateOperandSize(NaClInstState* state) { | |
| 223 return state->operand_size; | |
| 224 } | |
| 225 | |
| 226 uint8_t NaClInstStateAddressSize(NaClInstState* state) { | |
| 227 return state->address_size; | |
| 228 } | |
| OLD | NEW |