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.
9 * Implements a xed decoder that can be used as a NaClEnumeratorDecoder.
12 #include "native_client/src/trusted/validator/x86/testing/enuminsts/enuminsts.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"
20 #define kBufferSize 1024
22 /* Defines the virtual table for the xed decoder. */
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. */
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. */
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];
48 /* Initialize xed state before we try to decode anything. */
49 static void XedSetup(void) {
51 xed_state_zero(&xed_decoder._xed_state);
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;
57 #if (NACL_TARGET_SUBARCH == 64)
58 xed_decoder._xed_state.mmode = XED_MACHINE_MODE_LONG_64;
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);
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);
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]");
89 xed_format_intel(&xed_decoder._xedd, xed_decoder._xed_disasm,
90 kBufferSize, xed_decoder._pc_address);
91 xed_decoder._has_xed_disasm = TRUE;
93 return xed_decoder._xed_disasm;
96 /* Returns the mnemonic name for the disassembled instruction. */
97 static const char* GetInstMnemonic(const NaClEnumerator* enumerator) {
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;
106 /* If reached, we haven't cached it, so find the name from the
107 * disassembled instruction, and cache it.
109 xtmp = allocated = strdup(Disassemble(enumerator));
111 /* Remove while prefixes found (i.e. ignore ordering) to get opcode. */
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;
124 strncpyto(xed_decoder._xed_opcode, xtmp, kBufferSize - char0, ' ');
126 /* Cache operand text to be processed before returning. */
127 xtmp += strlen(xed_decoder._xed_opcode);
129 /* Remove uninteresting decorations.
130 * NOTE: these patterns need to be ordered from most to least specific
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 ");
140 cstrncpy(xed_decoder._xed_operands, strip(xtmp), kBufferSize);
142 return xed_decoder._xed_opcode;
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;
151 /* Prints out the disassembled instruction. */
152 static void PrintInst(const NaClEnumerator* enumerator) {
155 NaClPcAddress pc_address = (NaClPcAddress) xed_decoder._pc_address;
156 printf(" XED: %"NACL_PRIxNaClPcAddressAll": ", pc_address);
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.
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]);
172 printf("%s\n", Disassemble(enumerator));
175 static size_t InstLength(const NaClEnumerator* enumerator) {
176 return (size_t) xed_decoder._xedd._decoded_length;
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);
183 return xed_decoder._xed_inst;
186 static size_t GetNumOperands(const NaClEnumerator* enumerator) {
187 return (size_t) xed_inst_noperands(GetXedInst());
190 #if NACL_TARGET_SUBARCH == 64
191 static int IsReservedReg(const xed_reg_enum_t reg) {
202 static int IsWriteAction(const xed_operand_action_enum_t 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:
214 static Bool WritesToReservedReg(const NaClEnumerator* enumerator,
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));
223 #elif NACL_TARGET_SUBARCH == 32
224 static Bool WritesToReservedReg(const NaClEnumerator* enumerator,
229 #error("Bad NACL_TARGET_SUBARCH")
232 static void InstallFlag(const NaClEnumerator* enumerator,
233 const char* flag_name,
234 const void* flag_address) {
237 /* Defines the registry function that creates a xed decoder, and returns
238 * the decoder to be registered.
240 NaClEnumeratorDecoder* RegisterXedDecoder(void) {
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;