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