Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/trusted/validator/x86/ncval_seg_sfi/ncdecode.c

Issue 625923004: Delete old x86 validator. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: rebase master Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « src/trusted/validator/x86/ncval_seg_sfi/ncdecode.h ('k') | src/trusted/validator/x86/ncval_seg_sfi/ncdecode_aux.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698