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 * ncdecode.c - table driven decoder for Native Client | |
9 * | |
10 * Most x86 decoders I've looked at are big case statements. While | |
11 * this organization is fairly transparent and obvious, it tends to | |
12 * lead to messy control flow (gotos, etc.) that make the decoder | |
13 * more complicated, hence harder to maintain and harder to validate. | |
14 * | |
15 * This decoder is table driven, which will hopefully result in | |
16 * substantially less code. Although the code+tables may be more | |
17 * lines of code than a decoder built around a switch statement, | |
18 * the smaller amount of actual procedural code and the regular | |
19 * structure of the tables should make it easier to understand, | |
20 * debug, and easier to become confident the decoder is correct. | |
21 * | |
22 * As it is specialized to Native Client, this decoder can also | |
23 * benefit from any exclusions or simplifications we decide to | |
24 * make in the dialect of x86 machine code accepted by Native | |
25 * Client. Any such simplifications should ultimately be easily | |
26 * recognized by inspection of the decoder configuration tables. | |
27 * ALSO, the decoder mostly needs to worry about accurate | |
28 * instruction lengths and finding opcodes. It does not need | |
29 * to completely resolve the operands of all instructions. | |
30 */ | |
31 | |
32 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h" | |
33 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/ncdecode_aux.h" | |
34 | |
35 #include <stdio.h> | |
36 #include <assert.h> | |
37 | |
38 #if NACL_TARGET_SUBARCH == 64 | |
39 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdecodetab_
64.h" | |
40 #else | |
41 #include "native_client/src/trusted/validator/x86/ncval_seg_sfi/gen/ncdecodetab_
32.h" | |
42 #endif | |
43 | |
44 /* To turn on debugging of instruction decoding, change value of | |
45 * DEBUGGING to 1. | |
46 */ | |
47 #define DEBUGGING 0 | |
48 | |
49 #include "native_client/src/shared/utils/debugging.h" | |
50 | |
51 #include "native_client/src/trusted/validator/x86/ncinstbuffer_inl.c" | |
52 #include "native_client/src/trusted/validator/x86/x86_insts_inl.c" | |
53 | |
54 /* Generates a print name for the given NCDecodeImmediateType. */ | |
55 static const char* NCDecodeImmediateTypeName(NCDecodeImmediateType type) { | |
56 DEBUG_OR_ERASE( | |
57 switch(type) { | |
58 case IMM_UNKNOWN: return "IMM_UNKNOWN"; | |
59 case IMM_NONE: return "IMM_NONE"; | |
60 case IMM_FIXED1: return "IMM_FIXED1"; | |
61 case IMM_FIXED2: return "IMM_FIXED2"; | |
62 case IMM_FIXED3: return "IMM_FIXED3"; | |
63 case IMM_FIXED4: return "IMM_FIXED4"; | |
64 case IMM_DATAV: return "IMM_DATAV"; | |
65 case IMM_ADDRV: return "IMM_ADDRV"; | |
66 case IMM_GROUP3_F6: return "IMM_GROUP3_F6"; | |
67 case IMM_GROUP3_F7: return "IMM_GROUP3_F7"; | |
68 case IMM_FARPTR: return "IMM_FARPTR"; | |
69 case IMM_MOV_DATAV: return "IMM_MOV_DATAV"; | |
70 default: assert(0); | |
71 }); | |
72 /* NOTREACHED */ | |
73 return NULL; | |
74 } | |
75 | |
76 /* Prints out the contents of the given OpInfo. Should only be called | |
77 * inside a DEBUG macro (i.e. for debugging only). | |
78 */ | |
79 static void PrintOpInfo(const struct OpInfo* info) { | |
80 DEBUG_OR_ERASE(printf("opinfo(%s, hasmrm=%u, immtype=%s, opinmrm=%d)\n", | |
81 NaClInstTypeString(info->insttype), | |
82 info->hasmrmbyte, | |
83 NCDecodeImmediateTypeName(info->immtype), | |
84 info->opinmrm)); | |
85 } | |
86 | |
87 /* later this will make decoding x87 instructions a bit more concise. */ | |
88 static const struct OpInfo* kDecodeX87Op[8] = { kDecode87D8, | |
89 kDecode87D9, | |
90 kDecode87DA, | |
91 kDecode87DB, | |
92 kDecode87DC, | |
93 kDecode87DD, | |
94 kDecode87DE, | |
95 kDecode87DF }; | |
96 | |
97 static Bool NullDecoderAction(const struct NCDecoderInst* dinst) { | |
98 UNREFERENCED_PARAMETER(dinst); | |
99 return TRUE; | |
100 } | |
101 static void NullDecoderMethod(struct NCDecoderState* dstate) { | |
102 UNREFERENCED_PARAMETER(dstate); | |
103 } | |
104 | |
105 /* API to virtual methods of a decoder state. */ | |
106 void NCDecoderStateNewSegment(NCDecoderState* tthis) { | |
107 (tthis->new_segment_fn)(tthis); | |
108 } | |
109 | |
110 static Bool NCDecoderStateApplyAction(NCDecoderState* tthis, | |
111 NCDecoderInst* dinst) { | |
112 return (tthis->action_fn)(dinst); | |
113 } | |
114 | |
115 static void NCDecoderStateSegmentationError(NCDecoderState* tthis) { | |
116 (tthis->segmentation_error_fn)(tthis); | |
117 } | |
118 | |
119 static void NCDecoderStateInternalError(NCDecoderState* tthis) { | |
120 (tthis->internal_error_fn)(tthis); | |
121 } | |
122 | |
123 /* Error Condition Handling */ | |
124 static void ErrorSegmentation(NCDecoderInst* dinst) { | |
125 NCDecoderState* dstate = dinst->dstate; | |
126 NaClErrorReporter* reporter = dstate->error_reporter; | |
127 (*reporter->printf)(dstate->error_reporter, "ErrorSegmentation\n"); | |
128 /* When the decoder is used by the NaCl validator */ | |
129 /* the validator provides an error handler that does */ | |
130 /* the necessary bookeeping to track these errors. */ | |
131 NCDecoderStateSegmentationError(dstate); | |
132 } | |
133 | |
134 static void ErrorInternal(NCDecoderInst* dinst) { | |
135 NCDecoderState* dstate = dinst->dstate; | |
136 NaClErrorReporter* reporter = dstate->error_reporter; | |
137 (*reporter->printf)(reporter, "ErrorInternal\n"); | |
138 /* When the decoder is used by the NaCl validator */ | |
139 /* the validator provides an error handler that does */ | |
140 /* the necessary bookeeping to track these errors. */ | |
141 NCDecoderStateInternalError(dstate); | |
142 } | |
143 | |
144 /* Defines how to handle errors found while parsing the memory segment. */ | |
145 static void NCRemainingMemoryInternalError(NCRemainingMemoryError error, | |
146 struct NCRemainingMemory* memory) { | |
147 /* Don't do anything for memory overflow! Let NCDecodeSegment generate | |
148 * the corresponding segmentation error. This allows us to back out overflow | |
149 * if a predefined nop is matched. | |
150 */ | |
151 if (NCRemainingMemoryOverflow != error) { | |
152 NCDecoderState* dstate = (NCDecoderState*) memory->error_fn_state; | |
153 NCRemainingMemoryReportError(error, memory); | |
154 ErrorInternal(&dstate->inst_buffer[dstate->cur_inst_index]); | |
155 } | |
156 } | |
157 | |
158 static INLINE void InitDecoder(struct NCDecoderInst* dinst) { | |
159 NCInstBytesInitInline(&dinst->inst.bytes); | |
160 dinst->inst.prefixbytes = 0; | |
161 dinst->inst.prefixmask = 0; | |
162 dinst->inst.opcode_prefixmask = 0; | |
163 dinst->inst.num_opbytes = 1; /* unless proven otherwise. */ | |
164 dinst->inst.hassibbyte = 0; | |
165 dinst->inst.mrm = 0; | |
166 dinst->inst.immtype = IMM_UNKNOWN; | |
167 dinst->inst.immbytes = 0; | |
168 dinst->inst.dispbytes = 0; | |
169 dinst->inst.rexprefix = 0; | |
170 dinst->inst.lock_prefix_index = kNoLockPrefixIndex; | |
171 dinst->opinfo = NULL; | |
172 } | |
173 | |
174 /* Returns the number of bytes defined for the operand of the instruction. */ | |
175 static int ExtractOperandSize(NCDecoderInst* dinst) { | |
176 if (NACL_TARGET_SUBARCH == 64 && | |
177 dinst->inst.rexprefix && dinst->inst.rexprefix & 0x8) { | |
178 return 8; | |
179 } | |
180 if (dinst->inst.prefixmask & kPrefixDATA16) { | |
181 return 2; | |
182 } | |
183 return 4; | |
184 } | |
185 | |
186 /* at most four prefix bytes are allowed */ | |
187 static void ConsumePrefixBytes(struct NCDecoderInst* dinst) { | |
188 uint8_t nb; | |
189 int ii; | |
190 uint32_t prefix_form; | |
191 | |
192 for (ii = 0; ii < kMaxPrefixBytes; ++ii) { | |
193 nb = NCRemainingMemoryGetNext(&dinst->dstate->memory); | |
194 prefix_form = kPrefixTable[nb]; | |
195 if (prefix_form == 0) return; | |
196 DEBUG( printf("Consume prefix[%d]: %02x => %x\n", ii, nb, prefix_form) ); | |
197 dinst->inst.prefixmask |= prefix_form; | |
198 dinst->inst.prefixmask |= kPrefixTable[nb]; | |
199 dinst->inst.prefixbytes += 1; | |
200 NCInstBytesReadInline(&dinst->inst.bytes); | |
201 DEBUG( printf(" prefix mask: %08x\n", dinst->inst.prefixmask) ); | |
202 if (NACL_TARGET_SUBARCH == 64 && prefix_form == kPrefixREX) { | |
203 dinst->inst.rexprefix = nb; | |
204 /* REX prefix must be last prefix. */ | |
205 return; | |
206 } | |
207 if (prefix_form == kPrefixLOCK) { | |
208 /* Note: we don't have to worry about duplicates, since | |
209 * ValidatePrefixes in ncvalidate.c will not allow such | |
210 * a possibility. | |
211 */ | |
212 dinst->inst.lock_prefix_index = (uint8_t) ii; | |
213 } | |
214 } | |
215 } | |
216 | |
217 static const struct OpInfo* GetExtendedOpInfo(NCDecoderInst* dinst, | |
218 uint8_t opbyte2) { | |
219 uint32_t pm; | |
220 pm = dinst->inst.prefixmask; | |
221 if ((pm & (kPrefixDATA16 | kPrefixREPNE | kPrefixREP)) == 0) { | |
222 return &kDecode0FXXOp[opbyte2]; | |
223 } else if (pm & kPrefixDATA16) { | |
224 dinst->inst.prefixmask &= ~kPrefixDATA16; | |
225 dinst->inst.opcode_prefixmask = kPrefixDATA16; | |
226 return &kDecode660FXXOp[opbyte2]; | |
227 } else if (pm & kPrefixREPNE) { | |
228 dinst->inst.prefixmask &= ~kPrefixREPNE; | |
229 dinst->inst.opcode_prefixmask = kPrefixREPNE; | |
230 return &kDecodeF20FXXOp[opbyte2]; | |
231 } else if (pm & kPrefixREP) { | |
232 dinst->inst.prefixmask &= ~kPrefixREP; | |
233 dinst->inst.opcode_prefixmask = kPrefixREP; | |
234 return &kDecodeF30FXXOp[opbyte2]; | |
235 } | |
236 ErrorInternal(dinst); | |
237 return dinst->opinfo; | |
238 } | |
239 | |
240 static void GetX87OpInfo(NCDecoderInst* dinst) { | |
241 /* WAIT is an x87 instruction but not in the coproc opcode space. */ | |
242 uint8_t op1 = NCInstBytesByteInline(&dinst->inst_bytes, | |
243 dinst->inst.prefixbytes); | |
244 if (op1 < kFirstX87Opcode || op1 > kLastX87Opcode) { | |
245 if (op1 != kWAITOp) ErrorInternal(dinst); | |
246 return; | |
247 } | |
248 dinst->opinfo = &kDecodeX87Op[op1 - kFirstX87Opcode][dinst->inst.mrm]; | |
249 DEBUG( printf("NACL_X87 op1 = %02x, ", op1); | |
250 PrintOpInfo(dinst->opinfo) ); | |
251 } | |
252 | |
253 static void ConsumeOpcodeBytes(NCDecoderInst* dinst) { | |
254 uint8_t opcode = NCInstBytesReadInline(&dinst->inst.bytes); | |
255 dinst->opinfo = &kDecode1ByteOp[opcode]; | |
256 DEBUG( printf("NACLi_1BYTE: opcode = %02x, ", opcode); | |
257 PrintOpInfo(dinst->opinfo) ); | |
258 if (opcode == kTwoByteOpcodeByte1) { | |
259 uint8_t opcode2 = NCInstBytesReadInline(&dinst->inst.bytes); | |
260 dinst->opinfo = GetExtendedOpInfo(dinst, opcode2); | |
261 DEBUG( printf("NACLi_2BYTE: opcode2 = %02x, ", opcode2); | |
262 PrintOpInfo(dinst->opinfo) ); | |
263 dinst->inst.num_opbytes = 2; | |
264 if (dinst->opinfo->insttype == NACLi_3BYTE) { | |
265 uint8_t opcode3 = NCInstBytesReadInline(&dinst->inst.bytes); | |
266 uint32_t pm; | |
267 pm = dinst->inst.opcode_prefixmask; | |
268 dinst->inst.num_opbytes = 3; | |
269 | |
270 DEBUG( printf("NACLi_3BYTE: opcode3 = %02x, ", opcode3) ); | |
271 switch (opcode2) { | |
272 case 0x38: /* SSSE3, SSE4 */ | |
273 if (pm & kPrefixDATA16) { | |
274 dinst->opinfo = &kDecode660F38Op[opcode3]; | |
275 } else if (pm & kPrefixREPNE) { | |
276 dinst->opinfo = &kDecodeF20F38Op[opcode3]; | |
277 } else if (pm == 0) { | |
278 dinst->opinfo = &kDecode0F38Op[opcode3]; | |
279 } else { | |
280 /* Other prefixes like F3 cause an undefined instruction error. */ | |
281 /* Note from decoder table that NACLi_3BYTE is only used with */ | |
282 /* data16 and repne prefixes. */ | |
283 ErrorInternal(dinst); | |
284 } | |
285 break; | |
286 case 0x3A: /* SSSE3, SSE4 */ | |
287 if (pm & kPrefixDATA16) { | |
288 dinst->opinfo = &kDecode660F3AOp[opcode3]; | |
289 } else if (pm == 0) { | |
290 dinst->opinfo = &kDecode0F3AOp[opcode3]; | |
291 } else { | |
292 /* Other prefixes like F3 cause an undefined instruction error. */ | |
293 /* Note from decoder table that NACLi_3BYTE is only used with */ | |
294 /* data16 and repne prefixes. */ | |
295 ErrorInternal(dinst); | |
296 } | |
297 break; | |
298 default: | |
299 /* if this happens there is a decoding table bug */ | |
300 ErrorInternal(dinst); | |
301 break; | |
302 } | |
303 DEBUG( PrintOpInfo(dinst->opinfo) ); | |
304 } | |
305 } | |
306 dinst->inst.immtype = dinst->opinfo->immtype; | |
307 } | |
308 | |
309 static void ConsumeModRM(NCDecoderInst* dinst) { | |
310 if (dinst->opinfo->hasmrmbyte != 0) { | |
311 const uint8_t mrm = NCInstBytesReadInline(&dinst->inst.bytes); | |
312 DEBUG( printf("Mod/RM byte: %02x\n", mrm) ); | |
313 dinst->inst.mrm = mrm; | |
314 if (dinst->opinfo->insttype == NACLi_X87 || | |
315 dinst->opinfo->insttype == NACLi_X87_FSINCOS) { | |
316 GetX87OpInfo(dinst); | |
317 } | |
318 if (dinst->opinfo->opinmrm) { | |
319 const struct OpInfo* mopinfo = | |
320 &kDecodeModRMOp[dinst->opinfo->opinmrm][modrm_opcodeInline(mrm)]; | |
321 dinst->opinfo = mopinfo; | |
322 DEBUG( printf("NACLi_opinmrm: modrm.opcode = %x, ", | |
323 modrm_opcodeInline(mrm)); | |
324 PrintOpInfo(dinst->opinfo) ); | |
325 if (dinst->inst.immtype == IMM_UNKNOWN) { | |
326 assert(0); | |
327 dinst->inst.immtype = mopinfo->immtype; | |
328 } | |
329 /* handle weird case for 0xff TEST Ib/Iv */ | |
330 if (modrm_opcodeInline(mrm) == 0) { | |
331 if (dinst->inst.immtype == IMM_GROUP3_F6) { | |
332 dinst->inst.immtype = IMM_FIXED1; | |
333 } | |
334 if (dinst->inst.immtype == IMM_GROUP3_F7) { | |
335 dinst->inst.immtype = IMM_DATAV; | |
336 } | |
337 } | |
338 DEBUG( printf(" immtype = %s\n", | |
339 NCDecodeImmediateTypeName(dinst->inst.immtype)) ); | |
340 } | |
341 if (dinst->inst.prefixmask & kPrefixADDR16) { | |
342 switch (modrm_modInline(mrm)) { | |
343 case 0: | |
344 if (modrm_rmInline(mrm) == 0x06) { | |
345 dinst->inst.dispbytes = 2; /* disp16 */ | |
346 } else { | |
347 dinst->inst.dispbytes = 0; | |
348 } | |
349 break; | |
350 case 1: | |
351 dinst->inst.dispbytes = 1; /* disp8 */ | |
352 break; | |
353 case 2: | |
354 dinst->inst.dispbytes = 2; /* disp16 */ | |
355 break; | |
356 case 3: | |
357 dinst->inst.dispbytes = 0; /* no disp */ | |
358 break; | |
359 default: | |
360 ErrorInternal(dinst); | |
361 } | |
362 dinst->inst.hassibbyte = 0; | |
363 } else { | |
364 switch (modrm_modInline(mrm)) { | |
365 case 0: | |
366 if (modrm_rmInline(mrm) == 0x05) { | |
367 dinst->inst.dispbytes = 4; /* disp32 */ | |
368 } else { | |
369 dinst->inst.dispbytes = 0; | |
370 } | |
371 break; | |
372 case 1: | |
373 dinst->inst.dispbytes = 1; /* disp8 */ | |
374 break; | |
375 case 2: | |
376 dinst->inst.dispbytes = 4; /* disp32 */ | |
377 break; | |
378 case 3: | |
379 dinst->inst.dispbytes = 0; /* no disp */ | |
380 break; | |
381 default: | |
382 ErrorInternal(dinst); | |
383 } | |
384 dinst->inst.hassibbyte = ((modrm_rmInline(mrm) == 0x04) && | |
385 (modrm_modInline(mrm) != 3)); | |
386 } | |
387 } | |
388 DEBUG( printf(" dispbytes = %d, hasibbyte = %d\n", | |
389 dinst->inst.dispbytes, dinst->inst.hassibbyte) ); | |
390 } | |
391 | |
392 static INLINE void ConsumeSIB(NCDecoderInst* dinst) { | |
393 if (dinst->inst.hassibbyte != 0) { | |
394 const uint8_t sib = NCInstBytesReadInline(&dinst->inst.bytes); | |
395 if (sib_base(sib) == 0x05) { | |
396 switch (modrm_modInline(dinst->inst.mrm)) { | |
397 case 0: dinst->inst.dispbytes = 4; break; | |
398 case 1: dinst->inst.dispbytes = 1; break; | |
399 case 2: dinst->inst.dispbytes = 4; break; | |
400 case 3: | |
401 default: | |
402 ErrorInternal(dinst); | |
403 } | |
404 } | |
405 DEBUG( printf("sib byte: %02x, dispbytes = %d\n", | |
406 sib, dinst->inst.dispbytes) ); | |
407 } | |
408 } | |
409 | |
410 static INLINE void ConsumeID(NCDecoderInst* dinst) { | |
411 if (dinst->inst.immtype == IMM_UNKNOWN) { | |
412 ErrorInternal(dinst); | |
413 } | |
414 /* NOTE: NaCl allows at most one prefix byte (for 32-bit mode) */ | |
415 if (dinst->inst.immtype == IMM_MOV_DATAV) { | |
416 dinst->inst.immbytes = ExtractOperandSize(dinst); | |
417 } else if (dinst->inst.prefixmask & kPrefixDATA16) { | |
418 dinst->inst.immbytes = kImmTypeToSize66[dinst->inst.immtype]; | |
419 } else if (dinst->inst.prefixmask & kPrefixADDR16) { | |
420 dinst->inst.immbytes = kImmTypeToSize67[dinst->inst.immtype]; | |
421 } else { | |
422 dinst->inst.immbytes = kImmTypeToSize[dinst->inst.immtype]; | |
423 } | |
424 NCInstBytesReadBytesInline((ssize_t) dinst->inst.immbytes, | |
425 &dinst->inst.bytes); | |
426 NCInstBytesReadBytesInline((ssize_t) dinst->inst.dispbytes, | |
427 &dinst->inst.bytes); | |
428 DEBUG(printf("ID: %d disp bytes, %d imm bytes\n", | |
429 dinst->inst.dispbytes, dinst->inst.immbytes)); | |
430 } | |
431 | |
432 /* Actually this routine is special for 3DNow instructions */ | |
433 static INLINE void MaybeGet3ByteOpInfo(NCDecoderInst* dinst) { | |
434 if (dinst->opinfo->insttype == NACLi_3DNOW) { | |
435 uint8_t opbyte1 = NCInstBytesByteInline(&dinst->inst_bytes, | |
436 dinst->inst.prefixbytes); | |
437 uint8_t opbyte2 = NCInstBytesByteInline(&dinst->inst_bytes, | |
438 dinst->inst.prefixbytes + 1); | |
439 if (opbyte1 == kTwoByteOpcodeByte1 && | |
440 opbyte2 == k3DNowOpcodeByte2) { | |
441 uint8_t immbyte = | |
442 NCInstBytesByteInline(&dinst->inst_bytes, | |
443 dinst->inst.bytes.length - 1); | |
444 dinst->opinfo = &kDecode0F0FOp[immbyte]; | |
445 DEBUG( printf( | |
446 "NACLi_3DNOW: byte1 = %02x, byte2 = %02x, immbyte = %02x,\n ", | |
447 opbyte1, opbyte2, immbyte); | |
448 PrintOpInfo(dinst->opinfo) ); | |
449 } | |
450 } | |
451 } | |
452 | |
453 /* Gets an instruction nindex away from the given instruction. | |
454 * WARNING: Does not do bounds checking, other than rolling the | |
455 * index as needed to stay within the (circular) instruction buffer. | |
456 */ | |
457 static NCDecoderInst* NCGetInstDiff(const NCDecoderInst* dinst, | |
458 int nindex) { | |
459 /* Note: This code also handles increments, so that we can | |
460 * use the same code for both. | |
461 */ | |
462 size_t index = (dinst->inst_index + nindex) % dinst->dstate->inst_buffer_size; | |
463 return &dinst->dstate->inst_buffer[index]; | |
464 } | |
465 | |
466 struct NCDecoderInst* PreviousInst(const NCDecoderInst* dinst, | |
467 int nindex) { | |
468 if ((nindex > 0) && (((size_t) nindex) < dinst->inst_count)) { | |
469 return NCGetInstDiff(dinst, -nindex); | |
470 } else { | |
471 return NULL; | |
472 } | |
473 } | |
474 | |
475 /* Initialize the decoder state fields, assuming constructor parameter | |
476 * fields mbase, vbase, size, inst_buffer, and inst_buffer_size have | |
477 * already been set. | |
478 */ | |
479 static void NCDecoderStateInitFields(NCDecoderState* this) { | |
480 size_t dbindex; | |
481 this->error_reporter = &kNCNullErrorReporter; | |
482 NCRemainingMemoryInit(this->mbase, this->size, &this->memory); | |
483 this->memory.error_fn = NCRemainingMemoryInternalError; | |
484 this->memory.error_fn_state = (void*) this; | |
485 for (dbindex = 0; dbindex < this->inst_buffer_size; ++dbindex) { | |
486 this->inst_buffer[dbindex].dstate = this; | |
487 this->inst_buffer[dbindex].inst_index = dbindex; | |
488 this->inst_buffer[dbindex].inst_count = 1; | |
489 this->inst_buffer[dbindex].inst_addr = 0; | |
490 this->inst_buffer[dbindex].unchanged = FALSE; | |
491 NCInstBytesInitMemory(&this->inst_buffer[dbindex].inst.bytes, | |
492 &this->memory); | |
493 NCInstBytesPtrInit((NCInstBytesPtr*) &this->inst_buffer[dbindex].inst_bytes, | |
494 &this->inst_buffer[dbindex].inst.bytes); | |
495 } | |
496 this->cur_inst_index = 0; | |
497 } | |
498 | |
499 void NCDecoderStateConstruct(NCDecoderState* this, | |
500 uint8_t* mbase, NaClPcAddress vbase, | |
501 NaClMemorySize size, | |
502 NCDecoderInst* inst_buffer, | |
503 size_t inst_buffer_size) { | |
504 | |
505 /* Start by setting up virtual functions. */ | |
506 this->action_fn = NullDecoderAction; | |
507 this->new_segment_fn = NullDecoderMethod; | |
508 this->segmentation_error_fn = NullDecoderMethod; | |
509 this->internal_error_fn = NullDecoderMethod; | |
510 | |
511 /* Initialize the user-provided fields. */ | |
512 this->mbase = mbase; | |
513 this->vbase = vbase; | |
514 this->size = size; | |
515 this->inst_buffer = inst_buffer; | |
516 this->inst_buffer_size = inst_buffer_size; | |
517 | |
518 NCDecoderStateInitFields(this); | |
519 } | |
520 | |
521 void NCDecoderStateDestruct(NCDecoderState* this) { | |
522 /* Currently, there is nothing to do. */ | |
523 } | |
524 | |
525 /* "Printable" means the value returned by this function can be used for | |
526 * printing user-readable output, but it should not be used to influence if the | |
527 * validation algorithm passes or fails. The validation algorithm should not | |
528 * depend on vbase - in other words, it should not depend on where the code is | |
529 * being mapped in memory. | |
530 */ | |
531 static INLINE NaClPcAddress NCPrintableVLimit(NCDecoderState *dstate) { | |
532 return dstate->vbase + dstate->size; | |
533 } | |
534 | |
535 /* Modify the current instruction pointer to point to the next instruction | |
536 * in the ring buffer. Reset the state of that next instruction. | |
537 */ | |
538 static NCDecoderInst* IncrementInst(NCDecoderInst* inst) { | |
539 /* giving PreviousInst a positive number will get NextInst | |
540 * better to keep the buffer switching logic in one place | |
541 */ | |
542 NCDecoderInst* next_inst = NCGetInstDiff(inst, 1); | |
543 next_inst->inst_addr = inst->inst_addr + inst->inst.bytes.length; | |
544 next_inst->dstate->cur_inst_index = next_inst->inst_index; | |
545 next_inst->inst_count = inst->inst_count + 1; | |
546 next_inst->unchanged = FALSE; | |
547 return next_inst; | |
548 } | |
549 | |
550 /* Get the i-th byte of the current instruction being parsed. */ | |
551 static uint8_t GetInstByte(NCDecoderInst* dinst, ssize_t i) { | |
552 if (i < dinst->inst.bytes.length) { | |
553 return dinst->inst.bytes.byte[i]; | |
554 } else { | |
555 return NCRemainingMemoryLookaheadInline(&dinst->dstate->memory, | |
556 i - dinst->inst.bytes.length); | |
557 } | |
558 } | |
559 | |
560 /* Consume a predefined nop byte sequence, if a match can be found. | |
561 * Further, if found, replace the currently matched instruction with | |
562 * the consumed predefined nop. | |
563 */ | |
564 static void ConsumePredefinedNop(NCDecoderInst* dinst) { | |
565 /* Do maximal match of possible nops */ | |
566 uint8_t pos = 0; | |
567 struct OpInfo* matching_opinfo = NULL; | |
568 ssize_t matching_length = 0; | |
569 NCNopTrieNode* next = (NCNopTrieNode*) (kNcNopTrieNode + 0); | |
570 uint8_t byte = GetInstByte(dinst, pos); | |
571 while (NULL != next) { | |
572 if (byte == next->matching_byte) { | |
573 DEBUG(printf("NOP match byte: 0x%02x\n", (int) byte)); | |
574 byte = GetInstByte(dinst, ++pos); | |
575 if (NULL != next->matching_opinfo) { | |
576 DEBUG(printf("NOP matched rule! %d\n", pos)); | |
577 matching_opinfo = next->matching_opinfo; | |
578 matching_length = pos; | |
579 } | |
580 next = next->success; | |
581 } else { | |
582 next = next->fail; | |
583 } | |
584 } | |
585 if (NULL == matching_opinfo) { | |
586 DEBUG(printf("NOP match failed!\n")); | |
587 } else { | |
588 DEBUG(printf("NOP match succeeds! Using last matched rule.\n")); | |
589 NCRemainingMemoryResetInline(&dinst->dstate->memory); | |
590 InitDecoder(dinst); | |
591 NCInstBytesReadBytesInline(matching_length, &dinst->inst.bytes); | |
592 dinst->opinfo = matching_opinfo; | |
593 } | |
594 } | |
595 | |
596 /* If we didn't find a good instruction, try to consume one of the | |
597 * predefined NOP's. | |
598 */ | |
599 static void MaybeConsumePredefinedNop(NCDecoderInst* dinst) { | |
600 switch (dinst->opinfo->insttype) { | |
601 case NACLi_UNDEFINED: | |
602 case NACLi_INVALID: | |
603 case NACLi_ILLEGAL: | |
604 ConsumePredefinedNop(dinst); | |
605 break; | |
606 default: | |
607 break; | |
608 } | |
609 } | |
610 | |
611 /* All of the actions needed to read one additional instruction into mstate. | |
612 */ | |
613 void NCConsumeNextInstruction(struct NCDecoderInst* inst) { | |
614 DEBUG( printf("Decoding instruction at %"NACL_PRIxNaClPcAddress":\n", | |
615 inst->inst_addr) ); | |
616 InitDecoder(inst); | |
617 ConsumePrefixBytes(inst); | |
618 ConsumeOpcodeBytes(inst); | |
619 ConsumeModRM(inst); | |
620 ConsumeSIB(inst); | |
621 ConsumeID(inst); | |
622 MaybeGet3ByteOpInfo(inst); | |
623 MaybeConsumePredefinedNop(inst); | |
624 } | |
625 | |
626 void NCDecoderStateSetErrorReporter(NCDecoderState* this, | |
627 NaClErrorReporter* reporter) { | |
628 switch (reporter->supported_reporter) { | |
629 case NaClNullErrorReporter: | |
630 case NCDecoderInstErrorReporter: | |
631 this->error_reporter = reporter; | |
632 return; | |
633 default: | |
634 break; | |
635 } | |
636 (*reporter->printf)( | |
637 reporter, | |
638 "*** FATAL: using unsupported error reporter! ***\n" | |
639 "*** NCDecoderInstErrorReporter expected but found %s***\n", | |
640 NaClErrorReporterSupportedName(reporter->supported_reporter)); | |
641 exit(1); | |
642 } | |
643 | |
644 static void NCNullErrorPrintInst(NaClErrorReporter* self, | |
645 struct NCDecoderInst* inst) {} | |
646 | |
647 NaClErrorReporter kNCNullErrorReporter = { | |
648 NaClNullErrorReporter, | |
649 NaClNullErrorPrintf, | |
650 NaClNullErrorPrintfV, | |
651 (NaClPrintInst) NCNullErrorPrintInst, | |
652 }; | |
653 | |
654 Bool NCDecoderStateDecode(NCDecoderState* this) { | |
655 NCDecoderInst* dinst = &this->inst_buffer[this->cur_inst_index]; | |
656 DEBUG( printf("DecodeSegment(%p[%"NACL_PRIxNaClPcAddress"])\n", | |
657 (void*) this->memory.mpc, (NaClPcAddress) this->size) ); | |
658 NCDecoderStateNewSegment(this); | |
659 while (dinst->inst_addr < this->size) { | |
660 NCConsumeNextInstruction(dinst); | |
661 if (this->memory.overflow_count) { | |
662 NaClPcAddress newpc = (NCPrintableInstructionAddress(dinst) | |
663 + dinst->inst.bytes.length); | |
664 (*this->error_reporter->printf)( | |
665 this->error_reporter, | |
666 "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress | |
667 " (read overflow of %d bytes)\n", | |
668 newpc, NCPrintableVLimit(this), this->memory.overflow_count); | |
669 ErrorSegmentation(dinst); | |
670 return FALSE; | |
671 } | |
672 if (!NCDecoderStateApplyAction(this, dinst)) return FALSE; | |
673 /* get ready for next round */ | |
674 dinst = IncrementInst(dinst); | |
675 } | |
676 return TRUE; | |
677 } | |
678 | |
679 /* Default action for a decoder state pair. */ | |
680 static Bool NullNCDecoderStatePairAction(struct NCDecoderStatePair* tthis, | |
681 NCDecoderInst* old_inst, | |
682 NCDecoderInst* new_inst) { | |
683 return TRUE; | |
684 } | |
685 | |
686 void NCDecoderStatePairConstruct(NCDecoderStatePair* tthis, | |
687 NCDecoderState* old_dstate, | |
688 NCDecoderState* new_dstate, | |
689 NaClCopyInstructionFunc copy_func) { | |
690 tthis->old_dstate = old_dstate; | |
691 tthis->new_dstate = new_dstate; | |
692 tthis->action_fn = NullNCDecoderStatePairAction; | |
693 tthis->copy_func = copy_func; | |
694 } | |
695 | |
696 void NCDecoderStatePairDestruct(NCDecoderStatePair* tthis) { | |
697 } | |
698 | |
699 Bool NCDecoderStatePairDecode(NCDecoderStatePair* tthis) { | |
700 NCDecoderInst* old_dinst = | |
701 &tthis->old_dstate->inst_buffer[tthis->old_dstate->cur_inst_index]; | |
702 NCDecoderInst* new_dinst = | |
703 &tthis->new_dstate->inst_buffer[tthis->new_dstate->cur_inst_index]; | |
704 | |
705 /* Verify that the size of the code segments is the same, and has not | |
706 * been changed. | |
707 */ | |
708 if (tthis->old_dstate->size != tthis->new_dstate->size) { | |
709 /* If sizes differ, then they can't be the same, except for some | |
710 * (constant-sized) changes. Hence fail to decode. | |
711 */ | |
712 ErrorSegmentation(new_dinst); | |
713 return FALSE; | |
714 } | |
715 | |
716 /* Since the sizes of the segments are the same, only one limit | |
717 * needs to be checked. Hence, we will track the limit of the new | |
718 * decoder state. | |
719 */ | |
720 DEBUG( printf("NCDecoderStatePairDecode(%"NACL_PRIxNaClPcAddress")\n", | |
721 (NaClPcAddress) tthis->new_dstate->size)); | |
722 | |
723 /* Initialize decoder statements for decoding segment, by calling | |
724 * the corresponding virtual in the decoder. | |
725 */ | |
726 NCDecoderStateNewSegment(tthis->old_dstate); | |
727 NCDecoderStateNewSegment(tthis->new_dstate); | |
728 | |
729 /* Walk through both instruction segments, checking that | |
730 * they decode similarly. | |
731 */ | |
732 while (new_dinst->inst_addr < tthis->new_dstate->size) { | |
733 | |
734 NCConsumeNextInstruction(old_dinst); | |
735 NCConsumeNextInstruction(new_dinst); | |
736 | |
737 | |
738 /* Verify that the instruction lengths match. */ | |
739 if (old_dinst->inst.bytes.length != | |
740 new_dinst->inst.bytes.length) { | |
741 ErrorInternal(new_dinst); | |
742 return FALSE; | |
743 } | |
744 | |
745 /* Verify that we haven't walked past the end of the segment | |
746 * in either decoder state. | |
747 * | |
748 * Note: Since instruction lengths are the same, and the | |
749 * segment lengths are the same, if overflow occurs on one | |
750 * segment, it must occur on the other. | |
751 */ | |
752 if (new_dinst->inst_addr > tthis->new_dstate->size) { | |
753 NaClErrorReporter* reporter = new_dinst->dstate->error_reporter; | |
754 (*reporter->printf)( | |
755 reporter, | |
756 "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress"\n", | |
757 NCPrintableInstructionAddress(new_dinst), | |
758 NCPrintableVLimit(tthis->new_dstate)); | |
759 ErrorSegmentation(new_dinst); | |
760 return FALSE; | |
761 } | |
762 | |
763 /* Apply the action to the instructions, and continue | |
764 * only if the action succeeds. | |
765 */ | |
766 if (! (tthis->action_fn)(tthis, old_dinst, new_dinst)) { | |
767 return FALSE; | |
768 } | |
769 | |
770 /* Move to next instruction. */ | |
771 old_dinst = IncrementInst(old_dinst); | |
772 new_dinst = IncrementInst(new_dinst); | |
773 } | |
774 return TRUE; | |
775 } | |
OLD | NEW |