| 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 * xed_tester.c | |
| 9 * Implements a xed decoder that can be used as a NaClEnumeratorDecoder. | |
| 10 */ | |
| 11 | |
| 12 #include "native_client/src/trusted/validator/x86/testing/enuminsts/enuminsts.h" | |
| 13 | |
| 14 #include <string.h> | |
| 15 #include "xed-interface.h" | |
| 16 #include "native_client/src/trusted/validator/types_memory_model.h" | |
| 17 #include "native_client/src/trusted/validator/x86/ncinstbuffer.h" | |
| 18 #include "native_client/src/trusted/validator/x86/testing/enuminsts/str_utils.h" | |
| 19 | |
| 20 #define kBufferSize 1024 | |
| 21 | |
| 22 /* Defines the virtual table for the xed decoder. */ | |
| 23 struct { | |
| 24 /* The virtual table that implements this decoder. */ | |
| 25 NaClEnumeratorDecoder _base; | |
| 26 /* Defines the xed state to use to parse instructions. */ | |
| 27 xed_state_t _xed_state; | |
| 28 /* Defines the pc_address to assume when disassembling. */ | |
| 29 int _pc_address; | |
| 30 /* Defines the disassembled xed instruction. */ | |
| 31 xed_decoded_inst_t _xedd; | |
| 32 /* Defines the lower-level model of the disassembled xed instruction. */ | |
| 33 xed_inst_t const *_xed_inst; | |
| 34 /* Defines if there were errors parsing the instruction. */ | |
| 35 xed_error_enum_t _xed_error; | |
| 36 /* Defines whether we have disassembled the xed instruction. */ | |
| 37 Bool _has_xed_disasm; | |
| 38 /* If _has_xed_disam is true, the corresponding disassembly. */ | |
| 39 char _xed_disasm[kBufferSize]; | |
| 40 /* If non-empty, the corresponding instruction mnemonic. */ | |
| 41 char _xed_opcode[kBufferSize]; | |
| 42 /* Stores the corresponding operands of the instruction mnemonic. */ | |
| 43 char _xed_operands[kBufferSize]; | |
| 44 } xed_decoder; | |
| 45 | |
| 46 | |
| 47 | |
| 48 /* Initialize xed state before we try to decode anything. */ | |
| 49 static void XedSetup(void) { | |
| 50 xed_tables_init(); | |
| 51 xed_state_zero(&xed_decoder._xed_state); | |
| 52 | |
| 53 /* dstate.stack_addr_width = XED_ADDRESS_WIDTH_32b; */ | |
| 54 #if (NACL_TARGET_SUBARCH == 32) | |
| 55 xed_decoder._xed_state.mmode = XED_MACHINE_MODE_LONG_COMPAT_32; | |
| 56 #endif | |
| 57 #if (NACL_TARGET_SUBARCH == 64) | |
| 58 xed_decoder._xed_state.mmode = XED_MACHINE_MODE_LONG_64; | |
| 59 #endif | |
| 60 } | |
| 61 | |
| 62 /* Defines the function to parse the first instruction. */ | |
| 63 static void ParseInst(const NaClEnumerator* enumerator, const int pc_address) { | |
| 64 xed_decoder._has_xed_disasm = FALSE; | |
| 65 xed_decoder._pc_address = pc_address; | |
| 66 xed_decoder._xed_disasm[0] = 0; | |
| 67 xed_decoder._xed_opcode[0] = 0; | |
| 68 xed_decoder._xed_operands[0] = 0; | |
| 69 xed_decoder._xed_inst = NULL; | |
| 70 xed_decoded_inst_set_input_chip(&xed_decoder._xedd, XED_CHIP_CORE2); | |
| 71 xed_decoded_inst_zero_set_mode(&xed_decoder._xedd, &xed_decoder._xed_state); | |
| 72 xed_decoder._xed_error = xed_decode | |
| 73 (&xed_decoder._xedd, (const xed_uint8_t*)enumerator->_itext, | |
| 74 enumerator->_num_bytes); | |
| 75 } | |
| 76 | |
| 77 /* Returns true if the instruction parsed a legal instruction. */ | |
| 78 static Bool IsInstLegal(const NaClEnumerator* enumerator) { | |
| 79 return (xed_decoder._xedd._decoded_length != 0) && | |
| 80 (XED_ERROR_NONE == xed_decoder._xed_error); | |
| 81 } | |
| 82 | |
| 83 /* Returns the disassembled instruction. */ | |
| 84 static const char* Disassemble(const NaClEnumerator* enumerator) { | |
| 85 if (!xed_decoder._has_xed_disasm) { | |
| 86 if (xed_decoder._xedd._decoded_length == 0) { | |
| 87 strcpy(xed_decoder._xed_disasm, "[illegal instruction]"); | |
| 88 } | |
| 89 xed_format_intel(&xed_decoder._xedd, xed_decoder._xed_disasm, | |
| 90 kBufferSize, xed_decoder._pc_address); | |
| 91 xed_decoder._has_xed_disasm = TRUE; | |
| 92 } | |
| 93 return xed_decoder._xed_disasm; | |
| 94 } | |
| 95 | |
| 96 /* Returns the mnemonic name for the disassembled instruction. */ | |
| 97 static const char* GetInstMnemonic(const NaClEnumerator* enumerator) { | |
| 98 char *allocated; | |
| 99 char *xtmp; | |
| 100 char *prev_xtmp; | |
| 101 int char0 = 0; | |
| 102 | |
| 103 /* First see if we have cached it. If so, return it. */ | |
| 104 if (xed_decoder._xed_opcode[0] != 0) return xed_decoder._xed_opcode; | |
| 105 | |
| 106 /* If reached, we haven't cached it, so find the name from the | |
| 107 * disassembled instruction, and cache it. | |
| 108 */ | |
| 109 xtmp = allocated = strdup(Disassemble(enumerator)); | |
| 110 | |
| 111 /* Remove while prefixes found (i.e. ignore ordering) to get opcode. */ | |
| 112 while (1) { | |
| 113 xtmp = SkipPrefix(xtmp, "lock"); | |
| 114 xtmp = SkipPrefix(xtmp, "repne"); | |
| 115 xtmp = SkipPrefix(xtmp, "rep"); | |
| 116 xtmp = SkipPrefix(xtmp, "hint-not-taken"); | |
| 117 xtmp = SkipPrefix(xtmp, "hint-taken"); | |
| 118 xtmp = SkipPrefix(xtmp, "addr16"); | |
| 119 xtmp = SkipPrefix(xtmp, "addr32"); | |
| 120 xtmp = SkipPrefix(xtmp, "data16"); | |
| 121 if (xtmp == prev_xtmp) break; | |
| 122 prev_xtmp = xtmp; | |
| 123 } | |
| 124 strncpyto(xed_decoder._xed_opcode, xtmp, kBufferSize - char0, ' '); | |
| 125 | |
| 126 /* Cache operand text to be processed before returning. */ | |
| 127 xtmp += strlen(xed_decoder._xed_opcode); | |
| 128 | |
| 129 /* Remove uninteresting decorations. | |
| 130 * NOTE: these patterns need to be ordered from most to least specific | |
| 131 */ | |
| 132 CleanString(xtmp, "byte ptr "); | |
| 133 CleanString(xtmp, "dword ptr "); | |
| 134 CleanString(xtmp, "qword ptr "); | |
| 135 CleanString(xtmp, "xmmword ptr "); | |
| 136 CleanString(xtmp, "word ptr "); | |
| 137 CleanString(xtmp, "ptr "); | |
| 138 CleanString(xtmp, "far "); | |
| 139 | |
| 140 cstrncpy(xed_decoder._xed_operands, strip(xtmp), kBufferSize); | |
| 141 free(allocated); | |
| 142 return xed_decoder._xed_opcode; | |
| 143 } | |
| 144 | |
| 145 static const char* GetInstOperandsText(const NaClEnumerator* enumerator) { | |
| 146 /* Force caching of operands and return. */ | |
| 147 if (xed_decoder._xed_operands[0] == 0) GetInstMnemonic(enumerator); | |
| 148 return xed_decoder._xed_operands; | |
| 149 } | |
| 150 | |
| 151 /* Prints out the disassembled instruction. */ | |
| 152 static void PrintInst(const NaClEnumerator* enumerator) { | |
| 153 int i; | |
| 154 size_t opcode_size; | |
| 155 NaClPcAddress pc_address = (NaClPcAddress) xed_decoder._pc_address; | |
| 156 printf(" XED: %"NACL_PRIxNaClPcAddressAll": ", pc_address); | |
| 157 | |
| 158 /* Since xed doesn't print out opcode sequence, and it is | |
| 159 * useful to know, add it to the print out. Note: Use same | |
| 160 * spacing scheme as nacl decoder, so things line up. | |
| 161 */ | |
| 162 size_t num_bytes = MAX_INST_LENGTH; | |
| 163 if (enumerator->_num_bytes > num_bytes) | |
| 164 num_bytes = enumerator->_num_bytes; | |
| 165 for (i = 0; i < num_bytes; ++i) { | |
| 166 if (i < xed_decoder._xedd._decoded_length) { | |
| 167 printf("%02x ", enumerator->_itext[i]); | |
| 168 } else { | |
| 169 printf(" "); | |
| 170 } | |
| 171 } | |
| 172 printf("%s\n", Disassemble(enumerator)); | |
| 173 } | |
| 174 | |
| 175 static size_t InstLength(const NaClEnumerator* enumerator) { | |
| 176 return (size_t) xed_decoder._xedd._decoded_length; | |
| 177 } | |
| 178 | |
| 179 static inline xed_inst_t const* GetXedInst(void) { | |
| 180 if (xed_decoder._xed_inst == NULL) { | |
| 181 xed_decoder._xed_inst = xed_decoded_inst_inst(&xed_decoder._xedd); | |
| 182 } | |
| 183 return xed_decoder._xed_inst; | |
| 184 } | |
| 185 | |
| 186 static size_t GetNumOperands(const NaClEnumerator* enumerator) { | |
| 187 return (size_t) xed_inst_noperands(GetXedInst()); | |
| 188 } | |
| 189 | |
| 190 #if NACL_TARGET_SUBARCH == 64 | |
| 191 static int IsReservedReg(const xed_reg_enum_t reg) { | |
| 192 switch (reg) { | |
| 193 case XED_REG_RSP: | |
| 194 case XED_REG_RBP: | |
| 195 case XED_REG_R15: | |
| 196 return 1; | |
| 197 } | |
| 198 return 0; | |
| 199 } | |
| 200 | |
| 201 | |
| 202 static int IsWriteAction(const xed_operand_action_enum_t rw) { | |
| 203 switch (rw) { | |
| 204 case XED_OPERAND_ACTION_RW: | |
| 205 case XED_OPERAND_ACTION_W: | |
| 206 case XED_OPERAND_ACTION_RCW: | |
| 207 case XED_OPERAND_ACTION_CW: | |
| 208 case XED_OPERAND_ACTION_CRW: | |
| 209 return 1; | |
| 210 } | |
| 211 return 0; | |
| 212 } | |
| 213 | |
| 214 static Bool WritesToReservedReg(const NaClEnumerator* enumerator, | |
| 215 const size_t n) { | |
| 216 xed_inst_t const* xi = GetXedInst(); | |
| 217 xed_operand_t const* op = xed_inst_operand(xi, n); | |
| 218 xed_operand_enum_t op_name = xed_operand_name(op); | |
| 219 return xed_operand_is_register(op_name) && | |
| 220 IsReservedReg(xed_decoded_inst_get_reg(&xed_decoder._xedd, op_name)) && | |
| 221 IsWriteAction(xed_operand_rw(op)); | |
| 222 } | |
| 223 #elif NACL_TARGET_SUBARCH == 32 | |
| 224 static Bool WritesToReservedReg(const NaClEnumerator* enumerator, | |
| 225 const size_t n) { | |
| 226 return FALSE; | |
| 227 } | |
| 228 #else | |
| 229 #error("Bad NACL_TARGET_SUBARCH") | |
| 230 #endif | |
| 231 | |
| 232 static void InstallFlag(const NaClEnumerator* enumerator, | |
| 233 const char* flag_name, | |
| 234 const void* flag_address) { | |
| 235 } | |
| 236 | |
| 237 /* Defines the registry function that creates a xed decoder, and returns | |
| 238 * the decoder to be registered. | |
| 239 */ | |
| 240 NaClEnumeratorDecoder* RegisterXedDecoder(void) { | |
| 241 XedSetup(); | |
| 242 xed_decoder._base._id_name = "xed"; | |
| 243 xed_decoder._base._parse_inst_fn = ParseInst; | |
| 244 xed_decoder._base._inst_length_fn = InstLength; | |
| 245 xed_decoder._base._print_inst_fn = PrintInst; | |
| 246 xed_decoder._base._get_inst_mnemonic_fn = GetInstMnemonic; | |
| 247 xed_decoder._base._get_inst_num_operands_fn = GetNumOperands; | |
| 248 xed_decoder._base._get_inst_operands_text_fn = GetInstOperandsText; | |
| 249 xed_decoder._base._writes_to_reserved_reg_fn = WritesToReservedReg; | |
| 250 xed_decoder._base._is_inst_legal_fn = IsInstLegal; | |
| 251 xed_decoder._base._maybe_inst_validates_fn = NULL; | |
| 252 xed_decoder._base._segment_validates_fn = NULL; | |
| 253 xed_decoder._base._install_flag_fn = InstallFlag; | |
| 254 xed_decoder._base._usage_message = "Runs xed to decode instructions."; | |
| 255 return &xed_decoder._base; | |
| 256 } | |
| OLD | NEW |