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 0 : 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 0 : return NULL;
74 0 : }
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 0 : 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 0 : }
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 0 : static Bool NullDecoderAction(const struct NCDecoderInst* dinst) {
98 : UNREFERENCED_PARAMETER(dinst);
99 0 : return TRUE;
100 0 : }
101 2 : static void NullDecoderMethod(struct NCDecoderState* dstate) {
102 : UNREFERENCED_PARAMETER(dstate);
103 2 : }
104 :
105 : /* API to virtual methods of a decoder state. */
106 2 : void NCDecoderStateNewSegment(NCDecoderState* tthis) {
107 2 : (tthis->new_segment_fn)(tthis);
108 2 : }
109 :
110 : static Bool NCDecoderStateApplyAction(NCDecoderState* tthis,
111 2 : NCDecoderInst* dinst) {
112 2 : return (tthis->action_fn)(dinst);
113 2 : }
114 :
115 2 : static void NCDecoderStateSegmentationError(NCDecoderState* tthis) {
116 2 : (tthis->segmentation_error_fn)(tthis);
117 2 : }
118 :
119 0 : static void NCDecoderStateInternalError(NCDecoderState* tthis) {
120 0 : (tthis->internal_error_fn)(tthis);
121 0 : }
122 :
123 : /* Error Condition Handling */
124 2 : static void ErrorSegmentation(NCDecoderInst* dinst) {
125 2 : NCDecoderState* dstate = dinst->dstate;
126 2 : NaClErrorReporter* reporter = dstate->error_reporter;
127 2 : (*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 2 : NCDecoderStateSegmentationError(dstate);
132 2 : }
133 :
134 0 : static void ErrorInternal(NCDecoderInst* dinst) {
135 0 : NCDecoderState* dstate = dinst->dstate;
136 0 : NaClErrorReporter* reporter = dstate->error_reporter;
137 0 : (*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 0 : NCDecoderStateInternalError(dstate);
142 0 : }
143 :
144 : /* Defines how to handle errors found while parsing the memory segment. */
145 : static void NCRemainingMemoryInternalError(NCRemainingMemoryError error,
146 2 : 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 2 : if (NCRemainingMemoryOverflow != error) {
152 0 : NCDecoderState* dstate = (NCDecoderState*) memory->error_fn_state;
153 0 : NCRemainingMemoryReportError(error, memory);
154 0 : ErrorInternal(&dstate->inst_buffer[dstate->cur_inst_index]);
155 : }
156 2 : }
157 :
158 2 : static INLINE void InitDecoder(struct NCDecoderInst* dinst) {
159 2 : NCInstBytesInitInline(&dinst->inst.bytes);
160 2 : dinst->inst.prefixbytes = 0;
161 2 : dinst->inst.prefixmask = 0;
162 2 : dinst->inst.opcode_prefixmask = 0;
163 2 : dinst->inst.num_opbytes = 1; /* unless proven otherwise. */
164 2 : dinst->inst.hassibbyte = 0;
165 2 : dinst->inst.mrm = 0;
166 2 : dinst->inst.immtype = IMM_UNKNOWN;
167 2 : dinst->inst.immbytes = 0;
168 2 : dinst->inst.dispbytes = 0;
169 2 : dinst->inst.rexprefix = 0;
170 2 : dinst->inst.lock_prefix_index = kNoLockPrefixIndex;
171 2 : dinst->opinfo = NULL;
172 2 : }
173 :
174 : /* Returns the number of bytes defined for the operand of the instruction. */
175 2 : static int ExtractOperandSize(NCDecoderInst* dinst) {
176 : if (NACL_TARGET_SUBARCH == 64 &&
177 2 : dinst->inst.rexprefix && dinst->inst.rexprefix & 0x8) {
178 0 : return 8;
179 : }
180 2 : if (dinst->inst.prefixmask & kPrefixDATA16) {
181 2 : return 2;
182 : }
183 2 : return 4;
184 2 : }
185 :
186 : /* at most four prefix bytes are allowed */
187 2 : static void ConsumePrefixBytes(struct NCDecoderInst* dinst) {
188 : uint8_t nb;
189 : int ii;
190 : uint32_t prefix_form;
191 :
192 2 : for (ii = 0; ii < kMaxPrefixBytes; ++ii) {
193 2 : nb = NCRemainingMemoryGetNext(&dinst->dstate->memory);
194 2 : prefix_form = kPrefixTable[nb];
195 2 : if (prefix_form == 0) return;
196 2 : DEBUG( printf("Consume prefix[%d]: %02x => %x\n", ii, nb, prefix_form) );
197 2 : dinst->inst.prefixmask |= prefix_form;
198 2 : dinst->inst.prefixmask |= kPrefixTable[nb];
199 2 : dinst->inst.prefixbytes += 1;
200 2 : NCInstBytesReadInline(&dinst->inst.bytes);
201 2 : DEBUG( printf(" prefix mask: %08x\n", dinst->inst.prefixmask) );
202 2 : if (NACL_TARGET_SUBARCH == 64 && prefix_form == kPrefixREX) {
203 0 : dinst->inst.rexprefix = nb;
204 : /* REX prefix must be last prefix. */
205 0 : return;
206 : }
207 2 : 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 2 : dinst->inst.lock_prefix_index = (uint8_t) ii;
213 : }
214 2 : }
215 2 : }
216 :
217 : static const struct OpInfo* GetExtendedOpInfo(NCDecoderInst* dinst,
218 2 : uint8_t opbyte2) {
219 : uint32_t pm;
220 2 : pm = dinst->inst.prefixmask;
221 2 : if ((pm & (kPrefixDATA16 | kPrefixREPNE | kPrefixREP)) == 0) {
222 2 : return &kDecode0FXXOp[opbyte2];
223 2 : } else if (pm & kPrefixDATA16) {
224 2 : dinst->inst.prefixmask &= ~kPrefixDATA16;
225 2 : dinst->inst.opcode_prefixmask = kPrefixDATA16;
226 2 : return &kDecode660FXXOp[opbyte2];
227 2 : } else if (pm & kPrefixREPNE) {
228 1 : dinst->inst.prefixmask &= ~kPrefixREPNE;
229 1 : dinst->inst.opcode_prefixmask = kPrefixREPNE;
230 1 : return &kDecodeF20FXXOp[opbyte2];
231 2 : } else if (pm & kPrefixREP) {
232 2 : dinst->inst.prefixmask &= ~kPrefixREP;
233 2 : dinst->inst.opcode_prefixmask = kPrefixREP;
234 2 : return &kDecodeF30FXXOp[opbyte2];
235 : }
236 0 : ErrorInternal(dinst);
237 0 : return dinst->opinfo;
238 2 : }
239 :
240 2 : 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 2 : dinst->inst.prefixbytes);
244 2 : if (op1 < kFirstX87Opcode || op1 > kLastX87Opcode) {
245 0 : if (op1 != kWAITOp) ErrorInternal(dinst);
246 0 : return;
247 : }
248 2 : dinst->opinfo = &kDecodeX87Op[op1 - kFirstX87Opcode][dinst->inst.mrm];
249 : DEBUG( printf("NACL_X87 op1 = %02x, ", op1);
250 2 : PrintOpInfo(dinst->opinfo) );
251 2 : }
252 :
253 2 : static void ConsumeOpcodeBytes(NCDecoderInst* dinst) {
254 2 : uint8_t opcode = NCInstBytesReadInline(&dinst->inst.bytes);
255 2 : dinst->opinfo = &kDecode1ByteOp[opcode];
256 : DEBUG( printf("NACLi_1BYTE: opcode = %02x, ", opcode);
257 2 : PrintOpInfo(dinst->opinfo) );
258 2 : if (opcode == kTwoByteOpcodeByte1) {
259 2 : uint8_t opcode2 = NCInstBytesReadInline(&dinst->inst.bytes);
260 2 : dinst->opinfo = GetExtendedOpInfo(dinst, opcode2);
261 : DEBUG( printf("NACLi_2BYTE: opcode2 = %02x, ", opcode2);
262 2 : PrintOpInfo(dinst->opinfo) );
263 2 : dinst->inst.num_opbytes = 2;
264 2 : if (dinst->opinfo->insttype == NACLi_3BYTE) {
265 1 : uint8_t opcode3 = NCInstBytesReadInline(&dinst->inst.bytes);
266 : uint32_t pm;
267 1 : pm = dinst->inst.opcode_prefixmask;
268 1 : dinst->inst.num_opbytes = 3;
269 :
270 1 : DEBUG( printf("NACLi_3BYTE: opcode3 = %02x, ", opcode3) );
271 1 : switch (opcode2) {
272 : case 0x38: /* SSSE3, SSE4 */
273 1 : if (pm & kPrefixDATA16) {
274 1 : dinst->opinfo = &kDecode660F38Op[opcode3];
275 1 : } else if (pm & kPrefixREPNE) {
276 1 : dinst->opinfo = &kDecodeF20F38Op[opcode3];
277 0 : } else if (pm == 0) {
278 0 : dinst->opinfo = &kDecode0F38Op[opcode3];
279 0 : } 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 0 : ErrorInternal(dinst);
284 : }
285 1 : break;
286 : case 0x3A: /* SSSE3, SSE4 */
287 1 : if (pm & kPrefixDATA16) {
288 1 : dinst->opinfo = &kDecode660F3AOp[opcode3];
289 0 : } else if (pm == 0) {
290 0 : dinst->opinfo = &kDecode0F3AOp[opcode3];
291 0 : } 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 0 : ErrorInternal(dinst);
296 : }
297 1 : break;
298 : default:
299 : /* if this happens there is a decoding table bug */
300 0 : ErrorInternal(dinst);
301 : break;
302 : }
303 1 : DEBUG( PrintOpInfo(dinst->opinfo) );
304 : }
305 : }
306 2 : dinst->inst.immtype = dinst->opinfo->immtype;
307 2 : }
308 :
309 2 : static void ConsumeModRM(NCDecoderInst* dinst) {
310 2 : if (dinst->opinfo->hasmrmbyte != 0) {
311 2 : const uint8_t mrm = NCInstBytesReadInline(&dinst->inst.bytes);
312 2 : DEBUG( printf("Mod/RM byte: %02x\n", mrm) );
313 2 : dinst->inst.mrm = mrm;
314 : if (dinst->opinfo->insttype == NACLi_X87 ||
315 2 : dinst->opinfo->insttype == NACLi_X87_FSINCOS) {
316 2 : GetX87OpInfo(dinst);
317 : }
318 2 : if (dinst->opinfo->opinmrm) {
319 : const struct OpInfo* mopinfo =
320 2 : &kDecodeModRMOp[dinst->opinfo->opinmrm][modrm_opcodeInline(mrm)];
321 2 : dinst->opinfo = mopinfo;
322 : DEBUG( printf("NACLi_opinmrm: modrm.opcode = %x, ",
323 : modrm_opcodeInline(mrm));
324 2 : PrintOpInfo(dinst->opinfo) );
325 2 : if (dinst->inst.immtype == IMM_UNKNOWN) {
326 0 : assert(0);
327 0 : dinst->inst.immtype = mopinfo->immtype;
328 : }
329 : /* handle weird case for 0xff TEST Ib/Iv */
330 2 : if (modrm_opcodeInline(mrm) == 0) {
331 2 : if (dinst->inst.immtype == IMM_GROUP3_F6) {
332 0 : dinst->inst.immtype = IMM_FIXED1;
333 : }
334 2 : if (dinst->inst.immtype == IMM_GROUP3_F7) {
335 0 : dinst->inst.immtype = IMM_DATAV;
336 : }
337 : }
338 : DEBUG( printf(" immtype = %s\n",
339 2 : NCDecodeImmediateTypeName(dinst->inst.immtype)) );
340 : }
341 2 : if (dinst->inst.prefixmask & kPrefixADDR16) {
342 2 : switch (modrm_modInline(mrm)) {
343 : case 0:
344 2 : if (modrm_rmInline(mrm) == 0x06) {
345 0 : dinst->inst.dispbytes = 2; /* disp16 */
346 0 : } else {
347 2 : dinst->inst.dispbytes = 0;
348 : }
349 2 : break;
350 : case 1:
351 2 : dinst->inst.dispbytes = 1; /* disp8 */
352 2 : break;
353 : case 2:
354 1 : dinst->inst.dispbytes = 2; /* disp16 */
355 1 : break;
356 : case 3:
357 1 : dinst->inst.dispbytes = 0; /* no disp */
358 1 : break;
359 : default:
360 0 : ErrorInternal(dinst);
361 : }
362 2 : dinst->inst.hassibbyte = 0;
363 2 : } else {
364 2 : switch (modrm_modInline(mrm)) {
365 : case 0:
366 2 : if (modrm_rmInline(mrm) == 0x05) {
367 2 : dinst->inst.dispbytes = 4; /* disp32 */
368 2 : } else {
369 2 : dinst->inst.dispbytes = 0;
370 : }
371 2 : break;
372 : case 1:
373 2 : dinst->inst.dispbytes = 1; /* disp8 */
374 2 : break;
375 : case 2:
376 2 : dinst->inst.dispbytes = 4; /* disp32 */
377 2 : break;
378 : case 3:
379 2 : dinst->inst.dispbytes = 0; /* no disp */
380 2 : break;
381 : default:
382 0 : ErrorInternal(dinst);
383 : }
384 : dinst->inst.hassibbyte = ((modrm_rmInline(mrm) == 0x04) &&
385 2 : (modrm_modInline(mrm) != 3));
386 : }
387 : }
388 : DEBUG( printf(" dispbytes = %d, hasibbyte = %d\n",
389 2 : dinst->inst.dispbytes, dinst->inst.hassibbyte) );
390 2 : }
391 :
392 2 : static INLINE void ConsumeSIB(NCDecoderInst* dinst) {
393 2 : if (dinst->inst.hassibbyte != 0) {
394 2 : const uint8_t sib = NCInstBytesReadInline(&dinst->inst.bytes);
395 2 : if (sib_base(sib) == 0x05) {
396 2 : switch (modrm_modInline(dinst->inst.mrm)) {
397 2 : case 0: dinst->inst.dispbytes = 4; break;
398 2 : case 1: dinst->inst.dispbytes = 1; break;
399 0 : case 2: dinst->inst.dispbytes = 4; break;
400 : case 3:
401 : default:
402 0 : ErrorInternal(dinst);
403 : }
404 : }
405 : DEBUG( printf("sib byte: %02x, dispbytes = %d\n",
406 2 : sib, dinst->inst.dispbytes) );
407 : }
408 2 : }
409 :
410 2 : static INLINE void ConsumeID(NCDecoderInst* dinst) {
411 2 : if (dinst->inst.immtype == IMM_UNKNOWN) {
412 0 : ErrorInternal(dinst);
413 : }
414 : /* NOTE: NaCl allows at most one prefix byte (for 32-bit mode) */
415 2 : if (dinst->inst.immtype == IMM_MOV_DATAV) {
416 2 : dinst->inst.immbytes = ExtractOperandSize(dinst);
417 2 : } else if (dinst->inst.prefixmask & kPrefixDATA16) {
418 2 : dinst->inst.immbytes = kImmTypeToSize66[dinst->inst.immtype];
419 2 : } else if (dinst->inst.prefixmask & kPrefixADDR16) {
420 2 : dinst->inst.immbytes = kImmTypeToSize67[dinst->inst.immtype];
421 2 : } else {
422 2 : dinst->inst.immbytes = kImmTypeToSize[dinst->inst.immtype];
423 : }
424 : NCInstBytesReadBytesInline((ssize_t) dinst->inst.immbytes,
425 2 : &dinst->inst.bytes);
426 : NCInstBytesReadBytesInline((ssize_t) dinst->inst.dispbytes,
427 2 : &dinst->inst.bytes);
428 : DEBUG(printf("ID: %d disp bytes, %d imm bytes\n",
429 2 : dinst->inst.dispbytes, dinst->inst.immbytes));
430 2 : }
431 :
432 : /* Actually this routine is special for 3DNow instructions */
433 2 : static INLINE void MaybeGet3ByteOpInfo(NCDecoderInst* dinst) {
434 2 : if (dinst->opinfo->insttype == NACLi_3DNOW) {
435 : uint8_t opbyte1 = NCInstBytesByteInline(&dinst->inst_bytes,
436 1 : dinst->inst.prefixbytes);
437 : uint8_t opbyte2 = NCInstBytesByteInline(&dinst->inst_bytes,
438 1 : dinst->inst.prefixbytes + 1);
439 : if (opbyte1 == kTwoByteOpcodeByte1 &&
440 1 : opbyte2 == k3DNowOpcodeByte2) {
441 : uint8_t immbyte =
442 : NCInstBytesByteInline(&dinst->inst_bytes,
443 1 : dinst->inst.bytes.length - 1);
444 1 : dinst->opinfo = &kDecode0F0FOp[immbyte];
445 : DEBUG( printf(
446 : "NACLi_3DNOW: byte1 = %02x, byte2 = %02x, immbyte = %02x,\n ",
447 : opbyte1, opbyte2, immbyte);
448 1 : PrintOpInfo(dinst->opinfo) );
449 : }
450 : }
451 2 : }
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 2 : int nindex) {
459 : /* Note: This code also handles increments, so that we can
460 : * use the same code for both.
461 : */
462 2 : size_t index = (dinst->inst_index + nindex) % dinst->dstate->inst_buffer_size;
463 2 : return &dinst->dstate->inst_buffer[index];
464 2 : }
465 :
466 : struct NCDecoderInst* PreviousInst(const NCDecoderInst* dinst,
467 0 : int nindex) {
468 0 : if ((nindex > 0) && (((size_t) nindex) < dinst->inst_count)) {
469 0 : return NCGetInstDiff(dinst, -nindex);
470 : } else {
471 0 : return NULL;
472 : }
473 0 : }
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 2 : static void NCDecoderStateInitFields(NCDecoderState* this) {
480 : size_t dbindex;
481 2 : this->error_reporter = &kNCNullErrorReporter;
482 2 : NCRemainingMemoryInit(this->mbase, this->size, &this->memory);
483 2 : this->memory.error_fn = NCRemainingMemoryInternalError;
484 2 : this->memory.error_fn_state = (void*) this;
485 2 : for (dbindex = 0; dbindex < this->inst_buffer_size; ++dbindex) {
486 2 : this->inst_buffer[dbindex].dstate = this;
487 2 : this->inst_buffer[dbindex].inst_index = dbindex;
488 2 : this->inst_buffer[dbindex].inst_count = 1;
489 2 : this->inst_buffer[dbindex].inst_addr = 0;
490 2 : this->inst_buffer[dbindex].unchanged = FALSE;
491 : NCInstBytesInitMemory(&this->inst_buffer[dbindex].inst.bytes,
492 2 : &this->memory);
493 : NCInstBytesPtrInit((NCInstBytesPtr*) &this->inst_buffer[dbindex].inst_bytes,
494 2 : &this->inst_buffer[dbindex].inst.bytes);
495 2 : }
496 2 : this->cur_inst_index = 0;
497 2 : }
498 :
499 : void NCDecoderStateConstruct(NCDecoderState* this,
500 : uint8_t* mbase, NaClPcAddress vbase,
501 : NaClMemorySize size,
502 : NCDecoderInst* inst_buffer,
503 2 : size_t inst_buffer_size) {
504 :
505 : /* Start by setting up virtual functions. */
506 2 : this->action_fn = NullDecoderAction;
507 2 : this->new_segment_fn = NullDecoderMethod;
508 2 : this->segmentation_error_fn = NullDecoderMethod;
509 2 : this->internal_error_fn = NullDecoderMethod;
510 :
511 : /* Initialize the user-provided fields. */
512 2 : this->mbase = mbase;
513 2 : this->vbase = vbase;
514 2 : this->size = size;
515 2 : this->inst_buffer = inst_buffer;
516 2 : this->inst_buffer_size = inst_buffer_size;
517 :
518 2 : NCDecoderStateInitFields(this);
519 2 : }
520 :
521 2 : void NCDecoderStateDestruct(NCDecoderState* this) {
522 : /* Currently, there is nothing to do. */
523 2 : }
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 2 : static INLINE NaClPcAddress NCPrintableVLimit(NCDecoderState *dstate) {
532 2 : return dstate->vbase + dstate->size;
533 2 : }
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 2 : 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 2 : NCDecoderInst* next_inst = NCGetInstDiff(inst, 1);
543 2 : next_inst->inst_addr = inst->inst_addr + inst->inst.bytes.length;
544 2 : next_inst->dstate->cur_inst_index = next_inst->inst_index;
545 2 : next_inst->inst_count = inst->inst_count + 1;
546 2 : next_inst->unchanged = FALSE;
547 2 : return next_inst;
548 2 : }
549 :
550 : /* Get the i-th byte of the current instruction being parsed. */
551 2 : static uint8_t GetInstByte(NCDecoderInst* dinst, ssize_t i) {
552 2 : if (i < dinst->inst.bytes.length) {
553 2 : return dinst->inst.bytes.byte[i];
554 : } else {
555 : return NCRemainingMemoryLookaheadInline(&dinst->dstate->memory,
556 1 : i - dinst->inst.bytes.length);
557 : }
558 2 : }
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 2 : static void ConsumePredefinedNop(NCDecoderInst* dinst) {
565 : /* Do maximal match of possible nops */
566 2 : uint8_t pos = 0;
567 2 : struct OpInfo* matching_opinfo = NULL;
568 2 : ssize_t matching_length = 0;
569 2 : NCNopTrieNode* next = (NCNopTrieNode*) (kNcNopTrieNode + 0);
570 2 : uint8_t byte = GetInstByte(dinst, pos);
571 2 : while (NULL != next) {
572 2 : if (byte == next->matching_byte) {
573 2 : DEBUG(printf("NOP match byte: 0x%02x\n", (int) byte));
574 2 : byte = GetInstByte(dinst, ++pos);
575 2 : if (NULL != next->matching_opinfo) {
576 1 : DEBUG(printf("NOP matched rule! %d\n", pos));
577 1 : matching_opinfo = next->matching_opinfo;
578 1 : matching_length = pos;
579 : }
580 2 : next = next->success;
581 2 : } else {
582 2 : next = next->fail;
583 : }
584 2 : }
585 2 : if (NULL == matching_opinfo) {
586 2 : DEBUG(printf("NOP match failed!\n"));
587 2 : } else {
588 1 : DEBUG(printf("NOP match succeeds! Using last matched rule.\n"));
589 1 : NCRemainingMemoryResetInline(&dinst->dstate->memory);
590 1 : InitDecoder(dinst);
591 1 : NCInstBytesReadBytesInline(matching_length, &dinst->inst.bytes);
592 1 : dinst->opinfo = matching_opinfo;
593 : }
594 2 : }
595 :
596 : /* If we didn't find a good instruction, try to consume one of the
597 : * predefined NOP's.
598 : */
599 2 : static void MaybeConsumePredefinedNop(NCDecoderInst* dinst) {
600 2 : switch (dinst->opinfo->insttype) {
601 : case NACLi_UNDEFINED:
602 : case NACLi_INVALID:
603 : case NACLi_ILLEGAL:
604 2 : ConsumePredefinedNop(dinst);
605 : break;
606 : default:
607 : break;
608 : }
609 2 : }
610 :
611 : /* All of the actions needed to read one additional instruction into mstate.
612 : */
613 2 : void NCConsumeNextInstruction(struct NCDecoderInst* inst) {
614 : DEBUG( printf("Decoding instruction at %"NACL_PRIxNaClPcAddress":\n",
615 2 : inst->inst_addr) );
616 2 : InitDecoder(inst);
617 2 : ConsumePrefixBytes(inst);
618 2 : ConsumeOpcodeBytes(inst);
619 2 : ConsumeModRM(inst);
620 2 : ConsumeSIB(inst);
621 2 : ConsumeID(inst);
622 2 : MaybeGet3ByteOpInfo(inst);
623 2 : MaybeConsumePredefinedNop(inst);
624 2 : }
625 :
626 : void NCDecoderStateSetErrorReporter(NCDecoderState* this,
627 2 : NaClErrorReporter* reporter) {
628 2 : switch (reporter->supported_reporter) {
629 : case NaClNullErrorReporter:
630 : case NCDecoderInstErrorReporter:
631 2 : this->error_reporter = reporter;
632 2 : 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 0 : NaClErrorReporterSupportedName(reporter->supported_reporter));
641 0 : exit(1);
642 2 : }
643 :
644 : static void NCNullErrorPrintInst(NaClErrorReporter* self,
645 0 : struct NCDecoderInst* inst) {}
646 :
647 : NaClErrorReporter kNCNullErrorReporter = {
648 : NaClNullErrorReporter,
649 : NaClNullErrorPrintf,
650 : NaClNullErrorPrintfV,
651 : (NaClPrintInst) NCNullErrorPrintInst,
652 : };
653 :
654 2 : Bool NCDecoderStateDecode(NCDecoderState* this) {
655 2 : NCDecoderInst* dinst = &this->inst_buffer[this->cur_inst_index];
656 : DEBUG( printf("DecodeSegment(%p[%"NACL_PRIxNaClPcAddress"])\n",
657 2 : (void*) this->memory.mpc, (NaClPcAddress) this->size) );
658 2 : NCDecoderStateNewSegment(this);
659 2 : while (dinst->inst_addr < this->size) {
660 2 : NCConsumeNextInstruction(dinst);
661 2 : if (this->memory.overflow_count) {
662 : NaClPcAddress newpc = (NCPrintableInstructionAddress(dinst)
663 2 : + 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 2 : newpc, NCPrintableVLimit(this), this->memory.overflow_count);
669 2 : ErrorSegmentation(dinst);
670 2 : return FALSE;
671 : }
672 2 : if (!NCDecoderStateApplyAction(this, dinst)) return FALSE;
673 : /* get ready for next round */
674 2 : dinst = IncrementInst(dinst);
675 2 : }
676 2 : return TRUE;
677 2 : }
678 :
679 : /* Default action for a decoder state pair. */
680 : static Bool NullNCDecoderStatePairAction(struct NCDecoderStatePair* tthis,
681 : NCDecoderInst* old_inst,
682 0 : NCDecoderInst* new_inst) {
683 0 : return TRUE;
684 0 : }
685 :
686 : void NCDecoderStatePairConstruct(NCDecoderStatePair* tthis,
687 : NCDecoderState* old_dstate,
688 : NCDecoderState* new_dstate,
689 0 : NaClCopyInstructionFunc copy_func) {
690 0 : tthis->old_dstate = old_dstate;
691 0 : tthis->new_dstate = new_dstate;
692 0 : tthis->action_fn = NullNCDecoderStatePairAction;
693 0 : tthis->copy_func = copy_func;
694 0 : }
695 :
696 0 : void NCDecoderStatePairDestruct(NCDecoderStatePair* tthis) {
697 0 : }
698 :
699 0 : Bool NCDecoderStatePairDecode(NCDecoderStatePair* tthis) {
700 : NCDecoderInst* old_dinst =
701 0 : &tthis->old_dstate->inst_buffer[tthis->old_dstate->cur_inst_index];
702 : NCDecoderInst* new_dinst =
703 0 : &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 0 : 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 0 : ErrorSegmentation(new_dinst);
713 0 : 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 0 : (NaClPcAddress) tthis->new_dstate->size));
722 :
723 : /* Initialize decoder statements for decoding segment, by calling
724 : * the corresponding virtual in the decoder.
725 : */
726 0 : NCDecoderStateNewSegment(tthis->old_dstate);
727 0 : NCDecoderStateNewSegment(tthis->new_dstate);
728 :
729 : /* Walk through both instruction segments, checking that
730 : * they decode similarly.
731 : */
732 0 : while (new_dinst->inst_addr < tthis->new_dstate->size) {
733 :
734 0 : NCConsumeNextInstruction(old_dinst);
735 0 : NCConsumeNextInstruction(new_dinst);
736 :
737 :
738 : /* Verify that the instruction lengths match. */
739 : if (old_dinst->inst.bytes.length !=
740 0 : new_dinst->inst.bytes.length) {
741 0 : ErrorInternal(new_dinst);
742 0 : 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 0 : if (new_dinst->inst_addr > tthis->new_dstate->size) {
753 0 : NaClErrorReporter* reporter = new_dinst->dstate->error_reporter;
754 : (*reporter->printf)(
755 : reporter,
756 : "%"NACL_PRIxNaClPcAddress" > %"NACL_PRIxNaClPcAddress"\n",
757 : NCPrintableInstructionAddress(new_dinst),
758 0 : NCPrintableVLimit(tthis->new_dstate));
759 0 : ErrorSegmentation(new_dinst);
760 0 : return FALSE;
761 : }
762 :
763 : /* Apply the action to the instructions, and continue
764 : * only if the action succeeds.
765 : */
766 0 : if (! (tthis->action_fn)(tthis, old_dinst, new_dinst)) {
767 0 : return FALSE;
768 : }
769 :
770 : /* Move to next instruction. */
771 0 : old_dinst = IncrementInst(old_dinst);
772 0 : new_dinst = IncrementInst(new_dinst);
773 0 : }
774 0 : return TRUE;
775 0 : }
|