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