| 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 * ragel_tester.c | |
| 9 * Implements a ragel decoder that can be used as a NaClEnumeratorDecoder. | |
| 10 */ | |
| 11 #ifndef NACL_TRUSTED_BUT_NOT_TCB | |
| 12 #error("This file is not meant for use in the TCB.") | |
| 13 #endif | |
| 14 | |
| 15 #include "native_client/src/trusted/validator/x86/testing/enuminsts/enuminsts.h" | |
| 16 | |
| 17 #include <string.h> | |
| 18 #include "native_client/src/trusted/validator/types_memory_model.h" | |
| 19 #include "native_client/src/trusted/validator/x86/ncinstbuffer.h" | |
| 20 #include "native_client/src/trusted/validator/x86/testing/enuminsts/str_utils.h" | |
| 21 #include "native_client/src/trusted/validator_ragel/validator.h" | |
| 22 | |
| 23 #define kBufferSize 1024 | |
| 24 | |
| 25 /* Defines the virtual table for the ragel decoder. */ | |
| 26 struct { | |
| 27 /* The virtual table that implements this decoder. */ | |
| 28 NaClEnumeratorDecoder _base; | |
| 29 } ragel_decoder; | |
| 30 | |
| 31 /* Initialize ragel state before we try to decode anything. */ | |
| 32 static void RagelSetup(void) { | |
| 33 } | |
| 34 | |
| 35 struct RagelDecodeState { | |
| 36 const uint8_t *inst_offset; | |
| 37 uint8_t inst_num_bytes; | |
| 38 uint8_t first_call; | |
| 39 const char *inst_name; | |
| 40 int inst_is_legal; /* legal means decodes correctly */ | |
| 41 int inst_is_valid; /* valid means validator is happy */ | |
| 42 }; | |
| 43 struct RagelDecodeState RState; | |
| 44 | |
| 45 static const char* RGetInstMnemonic(const NaClEnumerator* enumerator) { | |
| 46 UNREFERENCED_PARAMETER(enumerator); | |
| 47 return RState.inst_name; | |
| 48 } | |
| 49 | |
| 50 static void RagelPrintInst(void) { | |
| 51 int i; | |
| 52 int print_num_bytes = RState.inst_num_bytes; | |
| 53 | |
| 54 if (print_num_bytes == 0) print_num_bytes = 4; | |
| 55 for (i = 0; i < print_num_bytes; i++) { | |
| 56 printf("%02x ", RState.inst_offset[i]); | |
| 57 } | |
| 58 printf("\n"); | |
| 59 } | |
| 60 | |
| 61 | |
| 62 Bool RagelInstruction(const uint8_t *begin, const uint8_t *end, | |
| 63 uint32_t info, void *userdata) { | |
| 64 struct RagelDecodeState *rstate = (struct RagelDecodeState *)userdata; | |
| 65 | |
| 66 /* Only look at the first instruction. */ | |
| 67 if (rstate->first_call) { | |
| 68 int restricted_register = | |
| 69 (info & RESTRICTED_REGISTER_MASK) >> RESTRICTED_REGISTER_SHIFT; | |
| 70 rstate->inst_num_bytes = (uint8_t)(end - begin); | |
| 71 | |
| 72 rstate->inst_is_valid = | |
| 73 !(info & (VALIDATION_ERRORS_MASK & ~DIRECT_JUMP_OUT_OF_RANGE)) && | |
| 74 restricted_register != REG_RSP && | |
| 75 restricted_register != REG_RBP; | |
| 76 rstate->inst_is_legal = rstate->inst_is_valid; | |
| 77 rstate->first_call = 0; | |
| 78 } | |
| 79 | |
| 80 if (info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET)) | |
| 81 return FALSE; | |
| 82 else | |
| 83 return TRUE; | |
| 84 } | |
| 85 | |
| 86 static void InitializeRagelDecodeState(struct RagelDecodeState *rs, | |
| 87 const uint8_t *itext) { | |
| 88 rs->first_call = 1; | |
| 89 rs->inst_offset = itext; | |
| 90 rs->inst_num_bytes = 0; | |
| 91 rs->inst_is_legal = 0; | |
| 92 rs->inst_is_valid = 0; | |
| 93 rs->inst_name = "undefined"; | |
| 94 } | |
| 95 | |
| 96 /* Defines the function to parse the first instruction. Note RState.ready */ | |
| 97 /* mechanism forces parsing of at most one instruction. */ | |
| 98 static void RParseInst(const NaClEnumerator* enumerator, const int pc_address) { | |
| 99 uint8_t chunk[(NACL_ENUM_MAX_INSTRUCTION_BYTES + kBundleMask) & | |
| 100 ~kBundleMask]; | |
| 101 | |
| 102 UNREFERENCED_PARAMETER(pc_address); | |
| 103 InitializeRagelDecodeState(&RState, enumerator->_itext); | |
| 104 | |
| 105 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_TARGET_SUBARCH == 64 | |
| 106 #define ValidateChunkArch ValidateChunkAMD64 | |
| 107 #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_TARGET_SUBARCH == 32 | |
| 108 #define ValidateChunkArch ValidateChunkIA32 | |
| 109 #else | |
| 110 #error("Unsupported architecture") | |
| 111 #endif | |
| 112 | |
| 113 /* Copy the command. */ | |
| 114 memcpy(chunk, enumerator->_itext, sizeof enumerator->_itext); | |
| 115 /* Fill the rest with HLTs. */ | |
| 116 memset(chunk + sizeof enumerator->_itext, 0xf4, | |
| 117 sizeof chunk - sizeof enumerator->_itext); | |
| 118 ValidateChunkArch(chunk, sizeof(chunk), | |
| 119 CALL_USER_CALLBACK_ON_EACH_INSTRUCTION, | |
| 120 &kFullCPUIDFeatures, | |
| 121 RagelInstruction, &RState); | |
| 122 | |
| 123 #undef ValidateChunkArch | |
| 124 } | |
| 125 | |
| 126 /* Returns true if the instruction parsed a legal instruction. */ | |
| 127 static Bool RIsInstLegal(const NaClEnumerator* enumerator) { | |
| 128 UNREFERENCED_PARAMETER(enumerator); | |
| 129 return RState.inst_is_legal; | |
| 130 } | |
| 131 | |
| 132 /* Returns true if the instruction parsed a legal instruction. */ | |
| 133 static Bool RIsInstValid(const NaClEnumerator* enumerator) { | |
| 134 UNREFERENCED_PARAMETER(enumerator); | |
| 135 return RState.inst_is_valid; | |
| 136 } | |
| 137 | |
| 138 /* Prints out the disassembled instruction. */ | |
| 139 static void RPrintInst(const NaClEnumerator* enumerator) { | |
| 140 UNREFERENCED_PARAMETER(enumerator); | |
| 141 printf("Ragel: "); | |
| 142 RagelPrintInst(); | |
| 143 } | |
| 144 | |
| 145 static size_t RInstLength(const NaClEnumerator* enumerator) { | |
| 146 UNREFERENCED_PARAMETER(enumerator); | |
| 147 return (size_t)RState.inst_num_bytes; | |
| 148 } | |
| 149 | |
| 150 static void InstallFlag(const NaClEnumerator* enumerator, | |
| 151 const char* flag_name, | |
| 152 const void* flag_address) { | |
| 153 UNREFERENCED_PARAMETER(enumerator); | |
| 154 UNREFERENCED_PARAMETER(flag_name); | |
| 155 UNREFERENCED_PARAMETER(flag_address); | |
| 156 } | |
| 157 | |
| 158 /* Defines the registry function that creates a ragel decoder, and returns | |
| 159 * the decoder to be registered. | |
| 160 */ | |
| 161 NaClEnumeratorDecoder* RegisterRagelDecoder(void) { | |
| 162 RagelSetup(); | |
| 163 ragel_decoder._base._id_name = "ragel"; | |
| 164 ragel_decoder._base._parse_inst_fn = RParseInst; | |
| 165 ragel_decoder._base._inst_length_fn = RInstLength; | |
| 166 ragel_decoder._base._print_inst_fn = RPrintInst; | |
| 167 ragel_decoder._base._is_inst_legal_fn = RIsInstLegal; | |
| 168 ragel_decoder._base._install_flag_fn = InstallFlag; | |
| 169 ragel_decoder._base._get_inst_mnemonic_fn = RGetInstMnemonic; | |
| 170 ragel_decoder._base._get_inst_num_operands_fn = NULL; | |
| 171 ragel_decoder._base._get_inst_operands_text_fn = NULL; | |
| 172 ragel_decoder._base._writes_to_reserved_reg_fn = NULL; | |
| 173 ragel_decoder._base._maybe_inst_validates_fn = RIsInstValid; | |
| 174 ragel_decoder._base._segment_validates_fn = NULL; | |
| 175 ragel_decoder._base._usage_message = "Runs ragel to decode instructions."; | |
| 176 return &ragel_decoder._base; | |
| 177 } | |
| OLD | NEW |