Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / validator / x86 / testing / enuminsts / xed_tester.c
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 }