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 |