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 * nacl_tester.c | |
9 * Uses the NaCl x86 validator/decoder to implement 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 <ctype.h> | |
18 #include <string.h> | |
19 #include "native_client/src/trusted/validator_x86/ncenuminsts.h" | |
20 #include "native_client/src/trusted/validator/x86/testing/enuminsts/str_utils.h" | |
21 | |
22 #define kBufferSize 1024 | |
23 | |
24 /* Defines the virtual table for the nacl decoder. */ | |
25 struct { | |
26 /* The virtual table that implements this decoder. */ | |
27 NaClEnumeratorDecoder _base; | |
28 /* Defines the NaCl state to use to parse instructions. */ | |
29 NaClInstStruct *_inst; | |
30 /* Defines if we are ignoring the instruction (i.e. an instruction | |
31 * that isn't xed implemented. | |
32 */ | |
33 Bool _ignore_instruction; | |
34 /* Defines the pc address associated with the instruction. */ | |
35 NaClPcAddress _pc_address; | |
36 /* If non-empty, the corresponding disassembly. */ | |
37 char _disassembly[kBufferSize]; | |
38 /* If non-empty, the simplified corresponding assembly, where | |
39 * the opcode byte sequence has been removed. | |
40 */ | |
41 char _simplified_disassembly[kBufferSize]; | |
42 /* If non-empty, the corresponding instruction mnemonic. */ | |
43 char _mnemonic[kBufferSize]; | |
44 /* if non-empty, the lowercase mnemonic. */ | |
45 char _mnemonic_lower[kBufferSize]; | |
46 /* If non-empty, stores the operands of the corresponding instruction. */ | |
47 char _operands[kBufferSize]; | |
48 /* True if we should translate special opcodes to matching xed nops. */ | |
49 Bool _translate_to_xed_nops; | |
50 /* True if we shouldn't accept instructions that aren't also implemented | |
51 * in xed. | |
52 */ | |
53 Bool _ignore_instructions_not_xed_implemented; | |
54 } nacl_decoder; | |
55 | |
56 static Bool IsInstLegal(const NaClEnumerator *enumerator) { | |
57 UNREFERENCED_PARAMETER(enumerator); | |
58 #if 0 | |
59 /* This forces an incorrect legality report for 00 24 c2, useful for */ | |
60 /* testing that related problems are being reported. */ | |
61 if (enumerator->_itext[0] == 0 && | |
62 enumerator->_itext[1] == 0x24 && | |
63 enumerator->_itext[2] == 0xc2) return 0; | |
64 #endif | |
65 return !nacl_decoder._ignore_instruction && | |
66 NaClInstDecodesCorrectly(nacl_decoder._inst); | |
67 } | |
68 | |
69 /* Instructions we assume that the NaCl validator accept and are valid, but | |
70 * are not legal according to xed. | |
71 */ | |
72 static Bool NaClIsntXedImplemented(const NaClEnumerator *enumerator) { | |
73 static const char* nacl_but_not_xed[] = { | |
74 "Pf2iw", | |
75 "Pf2id" | |
76 }; | |
77 const char* name = NaClOpcodeName(nacl_decoder._inst); | |
78 size_t i; | |
79 UNREFERENCED_PARAMETER(enumerator); | |
80 for (i = 0; i < NACL_ARRAY_SIZE(nacl_but_not_xed); ++i) { | |
81 if (0 == strcmp(name, nacl_but_not_xed[i])) { | |
82 return TRUE; | |
83 } | |
84 } | |
85 return FALSE; | |
86 } | |
87 | |
88 /* Defines the funcdtion to parse the first instruction. */ | |
89 static void ParseInst(const NaClEnumerator* enumerator, | |
90 const int pc_address) { | |
91 nacl_decoder._inst = NULL; | |
92 nacl_decoder._ignore_instruction = FALSE; | |
93 nacl_decoder._pc_address = pc_address; | |
94 nacl_decoder._disassembly[0] = 0; | |
95 nacl_decoder._simplified_disassembly[0] = 0; | |
96 nacl_decoder._mnemonic[0] = 0; | |
97 nacl_decoder._mnemonic_lower[0] = 0; | |
98 nacl_decoder._operands[0] = 0; | |
99 nacl_decoder._inst = | |
100 NaClParseInst((uint8_t *)enumerator->_itext, | |
101 enumerator->_num_bytes, pc_address); | |
102 if (nacl_decoder._ignore_instructions_not_xed_implemented && | |
103 IsInstLegal(enumerator)) { | |
104 nacl_decoder._ignore_instruction = NaClIsntXedImplemented(enumerator); | |
105 } | |
106 } | |
107 | |
108 | |
109 /* Returns the disassembled instruction. */ | |
110 static const char* Disassemble(const NaClEnumerator* enumerator) { | |
111 char* stmp; | |
112 | |
113 UNREFERENCED_PARAMETER(enumerator); | |
114 /* First see if we have cached it. If so, return it. */ | |
115 if (nacl_decoder._disassembly[0] != 0) return nacl_decoder._disassembly; | |
116 | |
117 stmp = NaClInstToStr(nacl_decoder._inst); | |
118 cstrncpy(nacl_decoder._disassembly, stmp, kBufferSize); | |
119 free(stmp); | |
120 return nacl_decoder._disassembly; | |
121 } | |
122 | |
123 /* Returns the lower case name of the instruction. */ | |
124 static const char* GetInstMnemonicLower(const NaClEnumerator* enumerator) { | |
125 char mnemonic[kBufferSize]; | |
126 size_t i; | |
127 | |
128 UNREFERENCED_PARAMETER(enumerator); | |
129 if (nacl_decoder._mnemonic_lower[0] != 0) | |
130 return nacl_decoder._mnemonic_lower; | |
131 | |
132 cstrncpy(mnemonic, NaClOpcodeName(nacl_decoder._inst), kBufferSize); | |
133 for (i = 0; i < kBufferSize; ++i) { | |
134 mnemonic[i] = tolower(mnemonic[i]); | |
135 if (mnemonic[i] == '\0') break; | |
136 } | |
137 cstrncpy(nacl_decoder._mnemonic_lower, mnemonic, kBufferSize); | |
138 return nacl_decoder._mnemonic_lower; | |
139 } | |
140 | |
141 /* Defines nacl/xed mnemonic renaming pairs. */ | |
142 typedef struct { | |
143 const char* nacl_name; | |
144 const char* xed_name; | |
145 } NaClToXedPairs; | |
146 | |
147 /* Returns the disassembled instruction with the opcode byte sequence | |
148 * removed. | |
149 */ | |
150 static const char* SimplifiedDisassembly(const NaClEnumerator *enumerator) { | |
151 const char* disassembly; | |
152 const char* mnemonic; | |
153 const char* start; | |
154 | |
155 /* First see if we have cache it. If so, return it. */ | |
156 if (nacl_decoder._simplified_disassembly[0] != 0) | |
157 return nacl_decoder._simplified_disassembly; | |
158 | |
159 /* Take first guess of simplified assembly. */ | |
160 /* Find start of instruction mnemonic, and define as start of simplified | |
161 * disassembly. | |
162 */ | |
163 disassembly = Disassemble(enumerator); | |
164 mnemonic = GetInstMnemonicLower(enumerator); | |
165 start = strfind(disassembly, mnemonic); | |
166 if (NULL == start) { | |
167 /* Don't know how to simplify, give up and just use disassembly. */ | |
168 cstrncpy(nacl_decoder._simplified_disassembly, disassembly, kBufferSize); | |
169 return nacl_decoder._simplified_disassembly; | |
170 } | |
171 cstrncpy(nacl_decoder._simplified_disassembly, start, kBufferSize); | |
172 rstrip(nacl_decoder._simplified_disassembly); | |
173 | |
174 /* Now handle special cases where we should treat the nacl instruction as a | |
175 * nop, so that they will match xed instructions. | |
176 */ | |
177 if (nacl_decoder._translate_to_xed_nops) { | |
178 static const NaClToXedPairs pairs[] = { | |
179 { "xchg %eax, %eax" , "nop" }, | |
180 { "xchg %rax, %rax" , "nop" }, | |
181 { "xchg %ax, %ax" , "nop" }, | |
182 }; | |
183 size_t i; | |
184 char buf[kBufferSize]; | |
185 const char* desc = strfind(nacl_decoder._simplified_disassembly, mnemonic); | |
186 if (NULL == desc) return nacl_decoder._simplified_disassembly; | |
187 cstrncpy(buf, desc, kBufferSize); | |
188 rstrip(buf); | |
189 for (i = 0; i < NACL_ARRAY_SIZE(pairs); ++i) { | |
190 if (0 == strcmp(nacl_decoder._simplified_disassembly, | |
191 pairs[i].nacl_name)) { | |
192 cstrncpy(nacl_decoder._simplified_disassembly, | |
193 pairs[i].xed_name, kBufferSize); | |
194 cstrncpy(nacl_decoder._mnemonic, pairs[i].xed_name, kBufferSize); | |
195 } | |
196 } | |
197 } | |
198 return nacl_decoder._simplified_disassembly; | |
199 } | |
200 | |
201 /* Returns the mnemonic name for the disassembled instruction. */ | |
202 static const char* GetInstMnemonic(const NaClEnumerator* enumerator) { | |
203 char mnemonic[kBufferSize]; | |
204 const char* disassembly; | |
205 | |
206 /* First see if we have cached it. If so, return it. */ | |
207 if (nacl_decoder._mnemonic[0] != 0) return nacl_decoder._mnemonic; | |
208 | |
209 /* Force simplifications if needed. Use mnemonic if defined. */ | |
210 disassembly = SimplifiedDisassembly(enumerator); | |
211 (void) disassembly; /* TODO(bradchen): use or remove this variable */ | |
212 if (nacl_decoder._mnemonic[0] != 0) return nacl_decoder._mnemonic; | |
213 | |
214 /* If reached, we haven't cached it, so find the name from the | |
215 * disassembled instruction and cache it. | |
216 */ | |
217 cstrncpy(mnemonic, GetInstMnemonicLower(enumerator), kBufferSize); | |
218 | |
219 /* Now fix mnemonic to corresponding xed name if needed. */ | |
220 if ((mnemonic[0] == 'p') && (mnemonic[1] == 'f') && (mnemonic[2] == 'r')) { | |
221 static const NaClToXedPairs pairs[] = { | |
222 { "pfrsqrt", "pfsqrt" }, | |
223 { "pfrcpit1", "pfcpit1" } | |
224 }; | |
225 size_t i; | |
226 for (i = 0; i < NACL_ARRAY_SIZE(pairs); ++i) { | |
227 if (0 == strcmp(mnemonic, pairs[i].nacl_name)) { | |
228 const char* start = | |
229 strfind(nacl_decoder._simplified_disassembly, mnemonic); | |
230 if (NULL != start) { | |
231 /* replace nacl_name with xed name in simplified disassembly. */ | |
232 cstrncpy(mnemonic, pairs[i].xed_name, kBufferSize); | |
233 } | |
234 } | |
235 } | |
236 } | |
237 | |
238 /* Install mnemonic and return. */ | |
239 cstrncpy(nacl_decoder._mnemonic, mnemonic, kBufferSize); | |
240 return nacl_decoder._mnemonic; | |
241 } | |
242 | |
243 /* Returns the text for the operands. To be used by the driver | |
244 * to compare accross decoders. | |
245 */ | |
246 static const char* GetInstOperandsText(const NaClEnumerator* enumerator) { | |
247 char operands[kBufferSize]; | |
248 const char* disassembly; | |
249 const char* after_mnemonic; | |
250 | |
251 /* First see if we have cached it. If so, return it. */ | |
252 if (nacl_decoder._operands[0] != 0) return nacl_decoder._operands; | |
253 | |
254 disassembly = SimplifiedDisassembly(enumerator); | |
255 after_mnemonic = strskip(disassembly, GetInstMnemonicLower(enumerator)); | |
256 if (NULL == after_mnemonic) after_mnemonic = disassembly; | |
257 cstrncpy(operands, after_mnemonic, kBufferSize); | |
258 strnzapchar(operands, '%'); | |
259 strnzapchar(operands, '\n'); | |
260 cstrncpy(nacl_decoder._operands, strip(operands), kBufferSize); | |
261 return nacl_decoder._operands; | |
262 } | |
263 | |
264 /* Prints out the disassembled instruction. */ | |
265 static void PrintInst(const NaClEnumerator* enumerator) { | |
266 printf(" NaCl: %s", Disassemble(enumerator)); | |
267 } | |
268 | |
269 /* Returns the number of bytes in the disassembled instruction. */ | |
270 static size_t InstLength(const NaClEnumerator* enumerator) { | |
271 UNREFERENCED_PARAMETER(enumerator); | |
272 #if 0 | |
273 /* This forces an incorrect length report for 00 24 c2, useful for */ | |
274 /* testing that length problems are being reported. */ | |
275 if (enumerator->_itext[0] == 0 && | |
276 enumerator->_itext[1] == 0x24 && | |
277 enumerator->_itext[2] == 0xc2) return 4; | |
278 #endif | |
279 return (size_t) NaClInstLength(nacl_decoder._inst); | |
280 } | |
281 | |
282 /* Returns true if the instruction decodes, and static (single instruction) | |
283 * validator tests pass. | |
284 */ | |
285 static Bool MaybeInstValidates(const NaClEnumerator *enumerator) { | |
286 return NaClInstValidates((uint8_t*) enumerator->_itext, | |
287 NaClInstLength(nacl_decoder._inst), | |
288 nacl_decoder._pc_address, | |
289 nacl_decoder._inst); | |
290 } | |
291 | |
292 /* Runs the validator on the given code segment. */ | |
293 static Bool SegmentValidates(const NaClEnumerator *enumerator, | |
294 const uint8_t* segment, | |
295 const size_t size, | |
296 const int pc_address) { | |
297 UNREFERENCED_PARAMETER(enumerator); | |
298 return NaClSegmentValidates((uint8_t*) segment, size, pc_address); | |
299 } | |
300 | |
301 /* Installs NaCl-specific flags. */ | |
302 static void InstallFlag(const NaClEnumerator* enumerator, | |
303 const char* flag_name, | |
304 const void* flag_address) { | |
305 UNREFERENCED_PARAMETER(enumerator); | |
306 if (0 == strcmp(flag_name, "--nops")) { | |
307 nacl_decoder._translate_to_xed_nops = *((Bool*) flag_address); | |
308 } else if (0 == strcmp(flag_name, "--xedimplemented")) { | |
309 nacl_decoder._ignore_instructions_not_xed_implemented = | |
310 *((Bool*) flag_address); | |
311 } | |
312 } | |
313 | |
314 /* Generates a decoder for the (sel_ldr) nacl validator. */ | |
315 NaClEnumeratorDecoder* RegisterNaClDecoder(void) { | |
316 nacl_decoder._base._id_name = "nacl"; | |
317 nacl_decoder._base._parse_inst_fn = ParseInst; | |
318 nacl_decoder._base._inst_length_fn = InstLength; | |
319 nacl_decoder._base._print_inst_fn = PrintInst; | |
320 nacl_decoder._base._get_inst_mnemonic_fn = GetInstMnemonic; | |
321 nacl_decoder._base._get_inst_num_operands_fn = NULL; | |
322 nacl_decoder._base._get_inst_operands_text_fn = GetInstOperandsText; | |
323 nacl_decoder._base._writes_to_reserved_reg_fn = NULL; | |
324 nacl_decoder._base._is_inst_legal_fn = IsInstLegal; | |
325 nacl_decoder._base._maybe_inst_validates_fn = MaybeInstValidates; | |
326 nacl_decoder._base._segment_validates_fn = SegmentValidates; | |
327 nacl_decoder._base._install_flag_fn = InstallFlag; | |
328 nacl_decoder._base._usage_message = | |
329 "Runs nacl decoder to decode instructions"; | |
330 return &nacl_decoder._base; | |
331 } | |
OLD | NEW |