OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | 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 | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /* | 7 /* |
8 * nacl_tester.c | 8 * nacl_tester.c |
9 * Uses the NaCl x86 validator/decoder to implement a NaClEnumeratorDecoder. | 9 * Uses the NaCl x86 validator/decoder to implement a NaClEnumeratorDecoder. |
10 */ | 10 */ |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 /* If non-empty, stores the operands of the corresponding instruction. */ | 42 /* If non-empty, stores the operands of the corresponding instruction. */ |
43 char _operands[kBufferSize]; | 43 char _operands[kBufferSize]; |
44 /* True if we should translate special opcodes to matching xed nops. */ | 44 /* True if we should translate special opcodes to matching xed nops. */ |
45 Bool _translate_to_xed_nops; | 45 Bool _translate_to_xed_nops; |
46 /* True if we shouldn't accept instructions that aren't also implemented | 46 /* True if we shouldn't accept instructions that aren't also implemented |
47 * in xed. | 47 * in xed. |
48 */ | 48 */ |
49 Bool _ignore_instructions_not_xed_implemented; | 49 Bool _ignore_instructions_not_xed_implemented; |
50 } nacl_decoder; | 50 } nacl_decoder; |
51 | 51 |
52 static Bool IsInstLegal(NaClEnumerator *enumerator) { | 52 static Bool IsInstLegal(const NaClEnumerator *enumerator) { |
53 return !nacl_decoder._ignore_instruction && | 53 return !nacl_decoder._ignore_instruction && |
54 NaClInstDecodesCorrectly(nacl_decoder._inst); | 54 NaClInstDecodesCorrectly(nacl_decoder._inst); |
55 } | 55 } |
56 | 56 |
57 /* Instructions we assume that the NaCl validator accept and are valid, but | 57 /* Instructions we assume that the NaCl validator accept and are valid, but |
58 * are not legal according to xed. | 58 * are not legal according to xed. |
59 */ | 59 */ |
60 static Bool NaClIsntXedImplemented(NaClEnumerator *enumerator) { | 60 static Bool NaClIsntXedImplemented(const NaClEnumerator *enumerator) { |
61 static const char* nacl_but_not_xed[] = { | 61 static const char* nacl_but_not_xed[] = { |
62 "Pf2iw", | 62 "Pf2iw", |
63 "Pf2id" | 63 "Pf2id" |
64 }; | 64 }; |
65 const char* name = NaClOpcodeName(nacl_decoder._inst); | 65 const char* name = NaClOpcodeName(nacl_decoder._inst); |
66 int i; | 66 int i; |
67 for (i = 0; i < NACL_ARRAY_SIZE(nacl_but_not_xed); ++i) { | 67 for (i = 0; i < NACL_ARRAY_SIZE(nacl_but_not_xed); ++i) { |
68 if (0 == strcmp(name, nacl_but_not_xed[i])) { | 68 if (0 == strcmp(name, nacl_but_not_xed[i])) { |
69 return TRUE; | 69 return TRUE; |
70 } | 70 } |
71 } | 71 } |
72 return FALSE; | 72 return FALSE; |
73 } | 73 } |
74 | 74 |
75 /* Defines the funcdtion to parse the first instruction. */ | 75 /* Defines the funcdtion to parse the first instruction. */ |
76 static void ParseInst(NaClEnumerator* enumerator, int pc_address) { | 76 static void ParseInst(const NaClEnumerator* enumerator, |
| 77 const int pc_address) { |
77 nacl_decoder._inst = NULL; | 78 nacl_decoder._inst = NULL; |
78 nacl_decoder._ignore_instruction = FALSE; | 79 nacl_decoder._ignore_instruction = FALSE; |
79 nacl_decoder._pc_address = pc_address; | 80 nacl_decoder._pc_address = pc_address; |
80 nacl_decoder._disassembly[0] = 0; | 81 nacl_decoder._disassembly[0] = 0; |
81 nacl_decoder._simplified_disassembly[0] = 0; | 82 nacl_decoder._simplified_disassembly[0] = 0; |
82 nacl_decoder._mnemonic[0] = 0; | 83 nacl_decoder._mnemonic[0] = 0; |
83 nacl_decoder._mnemonic_lower[0] = 0; | 84 nacl_decoder._mnemonic_lower[0] = 0; |
84 nacl_decoder._operands[0] = 0; | 85 nacl_decoder._operands[0] = 0; |
85 nacl_decoder._inst = | 86 nacl_decoder._inst = |
86 NaClParseInst(enumerator->_itext, enumerator->_num_bytes, pc_address); | 87 NaClParseInst((char*) enumerator->_itext, |
| 88 enumerator->_num_bytes, pc_address); |
87 if (nacl_decoder._ignore_instructions_not_xed_implemented && | 89 if (nacl_decoder._ignore_instructions_not_xed_implemented && |
88 IsInstLegal(enumerator)) { | 90 IsInstLegal(enumerator)) { |
89 nacl_decoder._ignore_instruction = NaClIsntXedImplemented(enumerator); | 91 nacl_decoder._ignore_instruction = NaClIsntXedImplemented(enumerator); |
90 } | 92 } |
91 } | 93 } |
92 | 94 |
93 | 95 |
94 /* Returns the disassembled instruction. */ | 96 /* Returns the disassembled instruction. */ |
95 static const char* Disassemble(NaClEnumerator* enumerator) { | 97 static const char* Disassemble(const NaClEnumerator* enumerator) { |
96 char* stmp; | 98 char* stmp; |
97 | 99 |
98 /* First see if we have cached it. If so, return it. */ | 100 /* First see if we have cached it. If so, return it. */ |
99 if (nacl_decoder._disassembly[0] != 0) return nacl_decoder._disassembly; | 101 if (nacl_decoder._disassembly[0] != 0) return nacl_decoder._disassembly; |
100 | 102 |
101 stmp = NaClInstToStr(nacl_decoder._inst); | 103 stmp = NaClInstToStr(nacl_decoder._inst); |
102 cstrncpy(nacl_decoder._disassembly, stmp, kBufferSize); | 104 cstrncpy(nacl_decoder._disassembly, stmp, kBufferSize); |
103 free(stmp); | 105 free(stmp); |
104 return nacl_decoder._disassembly; | 106 return nacl_decoder._disassembly; |
105 } | 107 } |
106 | 108 |
107 /* Returns the lower case name of the instruction. */ | 109 /* Returns the lower case name of the instruction. */ |
108 static const char* GetInstMnemonicLower(NaClEnumerator* enumerator) { | 110 static const char* GetInstMnemonicLower(const NaClEnumerator* enumerator) { |
109 char mnemonic[kBufferSize]; | 111 char mnemonic[kBufferSize]; |
110 size_t i; | 112 size_t i; |
111 | 113 |
112 if (nacl_decoder._mnemonic_lower[0] != 0) return nacl_decoder._mnemonic_lower; | 114 if (nacl_decoder._mnemonic_lower[0] != 0) return nacl_decoder._mnemonic_lower; |
113 | 115 |
114 cstrncpy(mnemonic, NaClOpcodeName(nacl_decoder._inst), kBufferSize); | 116 cstrncpy(mnemonic, NaClOpcodeName(nacl_decoder._inst), kBufferSize); |
115 for (i = 0; i < kBufferSize; ++i) { | 117 for (i = 0; i < kBufferSize; ++i) { |
116 mnemonic[i] = tolower(mnemonic[i]); | 118 mnemonic[i] = tolower(mnemonic[i]); |
117 if (mnemonic[i] == '\0') break; | 119 if (mnemonic[i] == '\0') break; |
118 } | 120 } |
119 cstrncpy(nacl_decoder._mnemonic_lower, mnemonic, kBufferSize); | 121 cstrncpy(nacl_decoder._mnemonic_lower, mnemonic, kBufferSize); |
120 return nacl_decoder._mnemonic_lower; | 122 return nacl_decoder._mnemonic_lower; |
121 } | 123 } |
122 | 124 |
123 /* Defines nacl/xed mnemonic renaming pairs. */ | 125 /* Defines nacl/xed mnemonic renaming pairs. */ |
124 typedef struct { | 126 typedef struct { |
125 const char* nacl_name; | 127 const char* nacl_name; |
126 const char* xed_name; | 128 const char* xed_name; |
127 } NaClToXedPairs; | 129 } NaClToXedPairs; |
128 | 130 |
129 /* Returns the disassembled instruction with the opcode byte sequence | 131 /* Returns the disassembled instruction with the opcode byte sequence |
130 * removed. | 132 * removed. |
131 */ | 133 */ |
132 static const char* SimplifiedDisassembly(NaClEnumerator *enumerator) { | 134 static const char* SimplifiedDisassembly(const NaClEnumerator *enumerator) { |
133 const char* disassembly; | 135 const char* disassembly; |
134 const char* mnemonic; | 136 const char* mnemonic; |
135 const char* start; | 137 const char* start; |
136 | 138 |
137 /* First see if we have cache it. If so, return it. */ | 139 /* First see if we have cache it. If so, return it. */ |
138 if (nacl_decoder._simplified_disassembly[0] != 0) | 140 if (nacl_decoder._simplified_disassembly[0] != 0) |
139 return nacl_decoder._simplified_disassembly; | 141 return nacl_decoder._simplified_disassembly; |
140 | 142 |
141 /* Take first guess of simplified assembly. */ | 143 /* Take first guess of simplified assembly. */ |
142 /* Find start of instruction mnemonic, and define as start of simplified | 144 /* Find start of instruction mnemonic, and define as start of simplified |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 cstrncpy(nacl_decoder._simplified_disassembly, | 176 cstrncpy(nacl_decoder._simplified_disassembly, |
175 pairs[i].xed_name, kBufferSize); | 177 pairs[i].xed_name, kBufferSize); |
176 cstrncpy(nacl_decoder._mnemonic, pairs[i].xed_name, kBufferSize); | 178 cstrncpy(nacl_decoder._mnemonic, pairs[i].xed_name, kBufferSize); |
177 return; | 179 return; |
178 } | 180 } |
179 } | 181 } |
180 } | 182 } |
181 } | 183 } |
182 | 184 |
183 /* Returns the mnemonic name for the disassembled instruction. */ | 185 /* Returns the mnemonic name for the disassembled instruction. */ |
184 static const char* GetInstMnemonic(NaClEnumerator* enumerator) { | 186 static const char* GetInstMnemonic(const NaClEnumerator* enumerator) { |
185 char mnemonic[kBufferSize]; | 187 char mnemonic[kBufferSize]; |
186 const char* disassembly; | 188 const char* disassembly; |
187 | 189 |
188 /* First see if we have cached it. If so, return it. */ | 190 /* First see if we have cached it. If so, return it. */ |
189 if (nacl_decoder._mnemonic[0] != 0) return nacl_decoder._mnemonic; | 191 if (nacl_decoder._mnemonic[0] != 0) return nacl_decoder._mnemonic; |
190 | 192 |
191 /* Force simplifications if needed. Use mnemonic if defined. */ | 193 /* Force simplifications if needed. Use mnemonic if defined. */ |
192 disassembly = SimplifiedDisassembly(enumerator); | 194 disassembly = SimplifiedDisassembly(enumerator); |
193 if (nacl_decoder._mnemonic[0] != 0) return nacl_decoder._mnemonic; | 195 if (nacl_decoder._mnemonic[0] != 0) return nacl_decoder._mnemonic; |
194 | 196 |
(...skipping 22 matching lines...) Expand all Loading... |
217 } | 219 } |
218 | 220 |
219 /* Install mnemonic and return. */ | 221 /* Install mnemonic and return. */ |
220 cstrncpy(nacl_decoder._mnemonic, mnemonic, kBufferSize); | 222 cstrncpy(nacl_decoder._mnemonic, mnemonic, kBufferSize); |
221 return nacl_decoder._mnemonic; | 223 return nacl_decoder._mnemonic; |
222 } | 224 } |
223 | 225 |
224 /* Returns the text for the operands. To be used by the driver | 226 /* Returns the text for the operands. To be used by the driver |
225 * to compare accross decoders. | 227 * to compare accross decoders. |
226 */ | 228 */ |
227 static const char* GetInstOperandsText(NaClEnumerator* enumerator) { | 229 static const char* GetInstOperandsText(const NaClEnumerator* enumerator) { |
228 char sbuf[kBufferSize]; | 230 char sbuf[kBufferSize]; |
229 char operands[kBufferSize]; | 231 char operands[kBufferSize]; |
230 const char* disassembly; | 232 const char* disassembly; |
231 const char* after_mnemonic; | 233 const char* after_mnemonic; |
232 | 234 |
233 /* First see if we have cached it. If so, return it. */ | 235 /* First see if we have cached it. If so, return it. */ |
234 if (nacl_decoder._operands[0] != 0) return nacl_decoder._operands; | 236 if (nacl_decoder._operands[0] != 0) return nacl_decoder._operands; |
235 | 237 |
236 disassembly = SimplifiedDisassembly(enumerator); | 238 disassembly = SimplifiedDisassembly(enumerator); |
237 after_mnemonic = strskip(disassembly, GetInstMnemonicLower(enumerator)); | 239 after_mnemonic = strskip(disassembly, GetInstMnemonicLower(enumerator)); |
238 if (NULL == after_mnemonic) after_mnemonic = disassembly; | 240 if (NULL == after_mnemonic) after_mnemonic = disassembly; |
239 cstrncpy(operands, after_mnemonic, kBufferSize); | 241 cstrncpy(operands, after_mnemonic, kBufferSize); |
240 strnzapchar(operands, '%'); | 242 strnzapchar(operands, '%'); |
241 strnzapchar(operands, '\n'); | 243 strnzapchar(operands, '\n'); |
242 cstrncpy(nacl_decoder._operands, strip(operands), kBufferSize); | 244 cstrncpy(nacl_decoder._operands, strip(operands), kBufferSize); |
243 return nacl_decoder._operands; | 245 return nacl_decoder._operands; |
244 } | 246 } |
245 | 247 |
246 /* Prints out the disassembled instruction. */ | 248 /* Prints out the disassembled instruction. */ |
247 static void PrintInst(NaClEnumerator* enumerator) { | 249 static void PrintInst(const NaClEnumerator* enumerator) { |
248 int i; | 250 printf(" NaCl: %s", Disassemble(enumerator)); |
249 uint8_t length = NaClInstLength(nacl_decoder._inst); | |
250 if (enumerator->_print_opcode_bytes_only) { | |
251 for (i = 0; i < length; ++i) { | |
252 printf("%02x", enumerator->_itext[i]); | |
253 } | |
254 printf("\n"); | |
255 } else { | |
256 if (enumerator->_print_enumerated_instruction) { | |
257 for (i = 0; i < length; ++i) { | |
258 printf("%02x ", enumerator->_itext[i]); | |
259 } | |
260 printf("#%s %s\n", GetInstMnemonic(enumerator), | |
261 GetInstOperandsText(enumerator)); | |
262 } else { | |
263 printf(" NaCl: %s", Disassemble(enumerator)); | |
264 } | |
265 } | |
266 } | 251 } |
267 | 252 |
268 /* Returns the number of bytes in the disassembled instruction. */ | 253 /* Returns the number of bytes in the disassembled instruction. */ |
269 static size_t InstLength(NaClEnumerator* enumerator) { | 254 static size_t InstLength(const NaClEnumerator* enumerator) { |
270 return (size_t) NaClInstLength(nacl_decoder._inst); | 255 return (size_t) NaClInstLength(nacl_decoder._inst); |
271 } | 256 } |
272 | 257 |
273 /* Returns true if the instruction decodes, and static (single instruction) | 258 /* Returns true if the instruction decodes, and static (single instruction) |
274 * validator tests pass. | 259 * validator tests pass. |
275 */ | 260 */ |
276 static Bool MaybeInstValidates(NaClEnumerator *enumerator) { | 261 static Bool MaybeInstValidates(const NaClEnumerator *enumerator) { |
277 return NaClInstValidates(enumerator->_itext, | 262 return NaClInstValidates((char*) enumerator->_itext, |
278 NaClInstLength(nacl_decoder._inst), | 263 NaClInstLength(nacl_decoder._inst), |
279 nacl_decoder._pc_address, | 264 nacl_decoder._pc_address, |
280 nacl_decoder._inst); | 265 nacl_decoder._inst); |
281 } | 266 } |
282 | 267 |
283 /* Runs the validator on the given code segment. */ | 268 /* Runs the validator on the given code segment. */ |
284 static Bool SegmentValidates(NaClEnumerator *enumerator, | 269 static Bool SegmentValidates(const NaClEnumerator *enumerator, |
285 uint8_t* segment, | 270 const uint8_t* segment, |
286 size_t size, | 271 const size_t size, |
287 int pc_address) { | 272 const int pc_address) { |
288 return NaClSegmentValidates(segment, size, pc_address); | 273 return NaClSegmentValidates((uint8_t*) segment, size, pc_address); |
289 } | 274 } |
290 | 275 |
291 /* Installs NaCl-specific flags. */ | 276 /* Installs NaCl-specific flags. */ |
292 static void InstallFlag(NaClEnumerator* enumerator, | 277 static void InstallFlag(const NaClEnumerator* enumerator, |
293 const char* flag_name, | 278 const char* flag_name, |
294 void* flag_address) { | 279 const void* flag_address) { |
295 if (0 == strcmp(flag_name, "--nops")) { | 280 if (0 == strcmp(flag_name, "--nops")) { |
296 nacl_decoder._translate_to_xed_nops = *((Bool*) flag_address); | 281 nacl_decoder._translate_to_xed_nops = *((Bool*) flag_address); |
297 } else if (0 == strcmp(flag_name, "--xedimplemented")) { | 282 } else if (0 == strcmp(flag_name, "--xedimplemented")) { |
298 nacl_decoder._ignore_instructions_not_xed_implemented = | 283 nacl_decoder._ignore_instructions_not_xed_implemented = |
299 *((Bool*) flag_address); | 284 *((Bool*) flag_address); |
300 } | 285 } |
301 } | 286 } |
302 | 287 |
303 /* Generates a decoder for the (sel_ldr) nacl validator. */ | 288 /* Generates a decoder for the (sel_ldr) nacl validator. */ |
304 NaClEnumeratorDecoder* RegisterNaClDecoder() { | 289 NaClEnumeratorDecoder* RegisterNaClDecoder() { |
305 nacl_decoder._base._id_name = "nacl"; | 290 nacl_decoder._base._id_name = "nacl"; |
306 nacl_decoder._base._legal_only = TRUE; | |
307 nacl_decoder._base._print_only = FALSE; | |
308 nacl_decoder._base._parse_inst_fn = ParseInst; | 291 nacl_decoder._base._parse_inst_fn = ParseInst; |
309 nacl_decoder._base._inst_length_fn = InstLength; | 292 nacl_decoder._base._inst_length_fn = InstLength; |
310 nacl_decoder._base._print_inst_fn = PrintInst; | 293 nacl_decoder._base._print_inst_fn = PrintInst; |
311 nacl_decoder._base._get_inst_mnemonic_fn = GetInstMnemonic; | 294 nacl_decoder._base._get_inst_mnemonic_fn = GetInstMnemonic; |
312 nacl_decoder._base._get_inst_num_operands_fn = NULL; | 295 nacl_decoder._base._get_inst_num_operands_fn = NULL; |
313 nacl_decoder._base._get_inst_operands_text_fn = GetInstOperandsText; | 296 nacl_decoder._base._get_inst_operands_text_fn = GetInstOperandsText; |
314 nacl_decoder._base._writes_to_reserved_reg_fn = NULL; | 297 nacl_decoder._base._writes_to_reserved_reg_fn = NULL; |
315 nacl_decoder._base._is_inst_legal_fn = IsInstLegal; | 298 nacl_decoder._base._is_inst_legal_fn = IsInstLegal; |
316 nacl_decoder._base._maybe_inst_validates_fn = MaybeInstValidates; | 299 nacl_decoder._base._maybe_inst_validates_fn = MaybeInstValidates; |
317 nacl_decoder._base._segment_validates_fn = SegmentValidates; | 300 nacl_decoder._base._segment_validates_fn = SegmentValidates; |
318 nacl_decoder._base._install_flag_fn = InstallFlag; | 301 nacl_decoder._base._install_flag_fn = InstallFlag; |
319 nacl_decoder._base._usage_message = | 302 nacl_decoder._base._usage_message = |
320 "Runs nacl decoder to decode instructions"; | 303 "Runs nacl decoder to decode instructions"; |
321 return &nacl_decoder._base; | 304 return &nacl_decoder._base; |
322 } | 305 } |
OLD | NEW |