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