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 : }
|