Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: src/trusted/validator/x86/decoder/ncop_exps.c

Issue 625923004: Delete old x86 validator. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: rebase master Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 #include "native_client/src/trusted/validator/x86/decoder/ncop_exps.h"
8
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <string.h>
12 #include <assert.h>
13 #include <sys/stat.h>
14
15 #include "native_client/src/include/portability.h"
16 #include "native_client/src/shared/platform/nacl_log.h"
17 #include "native_client/src/shared/utils/types.h"
18 #include "native_client/src/trusted/validator/x86/decoder/gen/ncop_expr_node_fla g_impl.h"
19 #include "native_client/src/trusted/validator/x86/decoder/gen/ncop_expr_node_kin d_impl.h"
20 #include "native_client/src/trusted/validator/x86/decoder/nc_decode_tables_types .h"
21 #include "native_client/src/trusted/validator/x86/decoder/nc_inst_state_internal .h"
22
23 /* To turn on debugging of instruction decoding, change value of
24 * DEBUGGING to 1.
25 *
26 * WARNING: Debugging messages inside of print messages must be sent to the
27 * same gio stream as being printed, since they may be used by another
28 * nacl log message that has locked the access to NaClLogGetGio().
29 */
30 #define DEBUGGING 0
31
32 #include "native_client/src/shared/utils/debugging.h"
33
34 #include "native_client/src/trusted/validator/x86/decoder/ncopcode_desc_inl.c"
35 #include "native_client/src/trusted/validator/x86/decoder/ncop_exps_inl.c"
36
37 void NaClPrintExpFlags(struct Gio* file, NaClExpFlags flags) {
38 if (flags == 0) {
39 gprintf(file, "0");
40 } else {
41 NaClExpFlag f;
42 Bool is_first = TRUE;
43 for (f = 0; f < NaClExpFlagEnumSize; f++) {
44 if (flags & NACL_EFLAG(f)) {
45 if (is_first) {
46 is_first = FALSE;
47 } else {
48 gprintf(file, " | ");
49 }
50 gprintf(file, "%s", NaClExpFlagName(f));
51 }
52 }
53 }
54 }
55
56 typedef struct NaClExpKindDescriptor {
57 /* The name of the expression operator. */
58 NaClExpKind name;
59 /* The rank (i.e. number of children) the expression operator has. */
60 const int rank;
61 } NaClExpKindDescriptor;
62
63 /* The print names of valid NaClExpKind values. */
64 static const NaClExpKindDescriptor
65 g_NaClExpKindDesc[NaClExpKindEnumSize + 1]= {
66 {UndefinedExp, 0},
67 {ExprRegister, 0},
68 {OperandReference, 1},
69 {ExprConstant, 0},
70 {ExprSegmentAddress, 2},
71 {ExprMemOffset, 4},
72 {ExprNaClIllegal, 0},
73 };
74
75 int NaClExpKindRank(NaClExpKind kind) {
76 assert(kind == g_NaClExpKindDesc[kind].name);
77 return g_NaClExpKindDesc[kind].rank;
78 }
79
80 /* Returns the register defined by the given node. */
81 NaClOpKind NaClGetExpRegister(NaClExp* node) {
82 return NaClGetExpRegisterInline(node);
83 }
84
85 /* Returns the name of the register defined by the indexed node in the
86 * vector of nodes.
87 */
88 NaClOpKind NaClGetExpVectorRegister(NaClExpVector* vector,
89 int node) {
90 return NaClGetExpRegisterInline(&vector->node[node]);
91 }
92
93 static int NaClPrintDisassembledExp(struct Gio* file,
94 NaClInstState* state,
95 uint32_t index);
96
97 /* Print the characters in the given string using lower case. */
98 static void NaClPrintLower(struct Gio* file, char* str) {
99 while (*str) {
100 gprintf(file, "%c", tolower(*str));
101 ++str;
102 }
103 }
104
105 /* Print out the given constant expression node to the given file. */
106 static void NaClPrintDisassembledConst(
107 struct Gio* file, NaClInstState* state, NaClExp* node) {
108 assert(node->kind == ExprConstant);
109 if (node->flags & NACL_EFLAG(ExprJumpTarget)) {
110 NaClPcAddress target = NaClInstStatePrintableAddress(state)
111 + state->bytes.length + (NaClPcNumber) NaClGetExprSignedValue(node);
112 gprintf(file, "0x%"NACL_PRIxNaClPcAddress, target);
113 }else if (node->flags & NACL_EFLAG(ExprUnsignedHex)) {
114 gprintf(file, "0x%"NACL_PRIx64, NaClGetExprUnsignedValue(node));
115 } else if (node->flags & NACL_EFLAG(ExprSignedHex)) {
116 int64_t val = NaClGetExprSignedValue(node);
117 if (val < 0) {
118 val = -val;
119 gprintf(file, "-0x%"NACL_PRIx64, val);
120 } else {
121 gprintf(file, "0x%"NACL_PRIx64, val);
122 }
123 } else if (node->flags & NACL_EFLAG(ExprUnsignedInt)) {
124 gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node));
125 } else {
126 /* Assume ExprSignedInt. */
127 gprintf(file, "%"NACL_PRId64, NaClGetExprSignedValue(node));
128 }
129 }
130
131 #define NACLOP_REG_PREFIX "Reg"
132
133 size_t NaClOpRegName(NaClOpKind reg, char* buffer, size_t buffer_size) {
134 const char* name = NaClOpKindName(reg);
135 char* str;
136 size_t index;
137
138 /* Fail if no room to put register name. */
139 if (buffer_size == 0) return 0;
140 buffer[0] = '\0'; /* To be safe, in case we exit prematurely. */
141
142 /* Get name for register. */
143 name = NaClOpKindName(reg);
144 if (NULL == name) return 0;
145
146 /* Strip off 'Reg' prefix from register name, if it exists. */
147 str = strstr(name, NACLOP_REG_PREFIX);
148 if (str != name) return 0;
149 str += strlen(NACLOP_REG_PREFIX);
150
151 /* Copy the name, converting characters to lower case. */
152 for (index = 0; (index + 1) < buffer_size; ++index) {
153 char ch = tolower(str[index]);
154 if ('\0' == ch) break;
155 buffer[index] = tolower(str[index]);
156 }
157
158 /* Be sure to add null character at end. */
159 buffer[index] = '\0';
160 return index;
161 }
162
163 #define MAX_REGISTER_SIZE 256
164
165 /* Print out the disassembled representation of the given register
166 * to the given file.
167 */
168 static void NaClPrintDisassembledRegKind(struct Gio* file, NaClOpKind reg) {
169 char buffer[MAX_REGISTER_SIZE];
170 NaClOpRegName(reg, buffer, MAX_REGISTER_SIZE);
171 gprintf(file, "%c%s", '%', buffer);
172 }
173
174 static INLINE void NaClPrintDisassembledReg(struct Gio* file, NaClExp* node) {
175 NaClPrintDisassembledRegKind(file, NaClGetExpRegisterInline(node));
176 }
177
178 void NaClExpVectorPrint(struct Gio* file, NaClInstState* state) {
179 uint32_t i;
180 NaClExpVector* vector = NaClInstStateExpVector(state);
181 gprintf(file, "NaClExpVector[%d] = {\n", vector->number_expr_nodes);
182 for (i = 0; i < vector->number_expr_nodes; i++) {
183 NaClExp* node = &vector->node[i];
184 gprintf(file, " { %s[%d] , ",
185 NaClExpKindName(node->kind),
186 NaClExpKindRank(node->kind));
187 switch (node->kind) {
188 case ExprRegister:
189 NaClPrintDisassembledReg(file, node);
190 break;
191 case ExprConstant:
192 NaClPrintDisassembledConst(file, state, node);
193 break;
194 default:
195 gprintf(file, "%"NACL_PRIu64, NaClGetExprUnsignedValue(node));
196 break;
197 }
198 gprintf(file, ", ");
199 NaClPrintExpFlags(file, node->flags);
200 gprintf(file, " },\n");
201 }
202 gprintf(file, "};\n");
203 }
204
205 /* Print out the given (memory offset) expression node to the given file.
206 * Returns the index of the node following the given (indexed) memory offset.
207 */
208 static int NaClPrintDisassembledMemOffset(struct Gio* file,
209 NaClInstState *state,
210 int index) {
211 NaClExpVector* vector = NaClInstStateExpVector(state);
212 int r1_index = index + 1;
213 int r2_index = r1_index + NaClExpWidth(vector, r1_index);
214 int scale_index = r2_index + NaClExpWidth(vector, r2_index);
215 int disp_index = scale_index + NaClExpWidth(vector, scale_index);
216 NaClOpKind r1 = NaClGetExpVectorRegister(vector, r1_index);
217 NaClOpKind r2 = NaClGetExpVectorRegister(vector, r2_index);
218 uint64_t scale = NaClGetExprUnsignedValue(&vector->node[scale_index]);
219 int64_t disp = NaClGetExprSignedValue(&vector->node[disp_index]);
220 assert(ExprMemOffset == vector->node[index].kind);
221 gprintf(file,"[");
222 if (r1 != RegUnknown) {
223 NaClPrintDisassembledRegKind(file, r1);
224 }
225 if (r2 != RegUnknown) {
226 if (r1 != RegUnknown) {
227 gprintf(file, "+");
228 }
229 NaClPrintDisassembledRegKind(file, r2);
230 gprintf(file, "*%d", (uint32_t) scale);
231 }
232 if (disp != 0) {
233 if ((r1 != RegUnknown || r2 != RegUnknown) &&
234 !NaClIsExpNegativeConstant(vector, disp_index)) {
235 gprintf(file, "+");
236 }
237 /* Recurse to handle print using format flags. */
238 NaClPrintDisassembledExp(file, state, disp_index);
239 } else if (r1 == RegUnknown && r2 == RegUnknown) {
240 /* be sure to generate case: [0x0]. */
241 NaClPrintDisassembledExp(file, state, disp_index);
242 }
243 gprintf(file, "]");
244 return disp_index + NaClExpWidth(vector, disp_index);
245 }
246
247 /* Retrurns true if the segment register of the indexed segment address is DS,
248 * and DS has been marked (by the instruction) as the default register
249 * for the segment address.
250 */
251 static Bool IsSegmentAddressDsRegPair(NaClInstState* state,
252 int index) {
253 NaClExpVector* vector = NaClInstStateExpVector(state);
254 NaClExp* segment_address = &vector->node[index];
255 NaClExp* segment_register =
256 &vector->node[NaClGetExpKidIndex(vector, index, 0)];
257 return NaClHasBit(segment_address->flags, NACL_EFLAG(ExprDSrCase)) &&
258 (segment_register->kind == ExprRegister) &&
259 (RegDS == NaClGetExpRegisterInline(segment_register));
260 }
261
262 /* Retrurns true if the segment register of the index segment address is ES,
263 * and ES has been marked (by the instruction) as the default register
264 * for the segment address.
265 */
266 static Bool IsSegmentAddressEsRegPair(NaClInstState* state,
267 int index) {
268 NaClExpVector* vector = NaClInstStateExpVector(state);
269 NaClExp* segment_address = &vector->node[index];
270 NaClExp* segment_register =
271 &vector->node[NaClGetExpKidIndex(vector, index, 0)];
272 return NaClHasBit(segment_address->flags, NACL_EFLAG(ExprESrCase)) &&
273 (segment_register->kind == ExprRegister) &&
274 (RegES == NaClGetExpRegisterInline(segment_register));
275 }
276
277 /* Print out the given (segment address) expression node to the
278 * given file. Returns the index of the node following the
279 * given (indexed) segment address.
280 */
281 static int NaClPrintDisassembledSegmentAddr(struct Gio* file,
282 NaClInstState* state,
283 int index) {
284 int memory_address;
285 NaClExpVector* vector = NaClInstStateExpVector(state);
286 /* If segment register is default. If so, do not print. */
287 if (IsSegmentAddressDsRegPair(state, index) ||
288 IsSegmentAddressEsRegPair(state, index)) {
289 /* Segment register matches default. Don't print. */
290 } else {
291 /* Print the segment register associated with the segment address. */
292 NaClPrintDisassembledExp(file, state, index + 1);
293 gprintf(file, ":");
294 }
295 memory_address = NaClGetExpKidIndex(vector, index, 1);
296 if (vector->node[memory_address].kind == ExprRegister) {
297 /* Special case segment address, where the register corresponds to
298 * a memory address. Print out the register in '[]' brackets to
299 * communicate that it is a memory reference.
300 */
301 int result;
302 gprintf(file, "[");
303 result = NaClPrintDisassembledExp(file, state, memory_address);
304 gprintf(file, "]");
305 return result;
306 } else {
307 /* print out memory address associated with segment address. */
308 return NaClPrintDisassembledExp(file, state, memory_address);
309 }
310 }
311
312 /* Print out the given expression node to the given file.
313 * Returns the index of the node following the given indexed
314 * expression.
315 */
316 static int NaClPrintDisassembledExp(struct Gio* file,
317 NaClInstState* state,
318 uint32_t index) {
319 NaClExp* node;
320 NaClExpVector* vector = NaClInstStateExpVector(state);
321 assert(index < vector->number_expr_nodes);
322 node = &vector->node[index];
323 switch (node->kind) {
324 default:
325 gprintf(file, "undefined");
326 return index + 1;
327 case ExprRegister:
328 NaClPrintDisassembledReg(file, node);
329 return index + 1;
330 case OperandReference:
331 return NaClPrintDisassembledExp(file, state, index + 1);
332 case ExprConstant:
333 NaClPrintDisassembledConst(file, state, node);
334 return index + 1;
335 case ExprSegmentAddress:
336 return NaClPrintDisassembledSegmentAddr(file, state, index);
337 case ExprMemOffset:
338 return NaClPrintDisassembledMemOffset(file, state, index);
339 case ExprNaClIllegal:
340 gprintf(file, "*NaClIllegal*");
341 return index + 1;
342 }
343 }
344
345 /* Returns true if there is a segment override in the segment address
346 * node defined by vector[seg_addr_index].
347 *
348 * Parameters:
349 * vector - The node expression tree associated with the instruction.
350 * seg_addr_index - The index to the segment address node to check.
351 * seg_eflag - The expr flag that must be associated with the
352 * segment address node to be considered for an override.
353 * seg_reg - The expected (i.e. default) segment register
354 * to be associated with the segment address.
355 */
356 static Bool NaClHasSegmentOverride(NaClExpVector* vector,
357 int seg_addr_index,
358 NaClExpFlag seg_eflag,
359 NaClOpKind seg_reg) {
360 NaClExp* seg_node = &vector->node[seg_addr_index];
361 if (seg_node->flags & NACL_EFLAG(seg_eflag)) {
362 int seg_index = seg_addr_index + 1;
363 NaClExp* node = &vector->node[seg_index];
364 if ((ExprRegister == node->kind) &&
365 (seg_reg != NaClGetExpRegisterInline(node))) {
366 return TRUE;
367 }
368 }
369 return FALSE;
370 }
371
372 /* Prints out the segment register associated with the segment
373 * address node defined by vector[seg_addr_index].
374 *
375 * Parameters:
376 * file - The Gio file to print the segment register to.
377 * is_first - True if the first operand of the instruction.
378 * vector - The node expression tree associated with the instruction.
379 * seg_addr_index - The index to the segment address node to check.
380 */
381 static void NaClPrintSegmentOverride(struct Gio* file,
382 Bool* is_first,
383 NaClInstState* state,
384 NaClExpVector* vector,
385 int seg_addr_index) {
386 int seg_index = seg_addr_index + 1;
387 if (*is_first) {
388 gprintf(file, " ");
389 *is_first = FALSE;
390 } else {
391 gprintf(file, ", ");
392 }
393 NaClPrintDisassembledExp(file, state, seg_index);
394 }
395
396 /* Print the flag name if the flag is defined for the corresponding operand.
397 * Used to print out set/use/zero extend information for partial instructions.
398 */
399 static void NaClPrintAddOperandFlag(struct Gio* f,
400 const NaClOp* op,
401 NaClOpFlag flag,
402 const char* flag_name) {
403 if (op->flags & NACL_OPFLAG(flag)) {
404 gprintf(f, "%s", flag_name);
405 }
406 }
407
408 /* Print the given instruction opcode of the give state, to the
409 * given file.
410 */
411 static void NaClPrintDisassembled(struct Gio* file,
412 NaClInstState* state,
413 const NaClInst* inst) {
414 uint32_t tree_index = 0;
415 Bool is_first = TRUE;
416 Bool not_printed_prefix_segment = TRUE;
417 NaClExp* node;
418 NaClExpVector* vector = NaClInstStateExpVector(state);
419
420 /* Print the name of the instruction. */
421 if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction))) {
422 /* Instruction has been simplified. Print out corresponding
423 * hints to the reader, so that they know that the instruction
424 * has been simplified.
425 */
426 gprintf(file, "[P] ");
427 NaClPrintLower(file, (char*) NaClMnemonicName(inst->name));
428 if (NaClHasBit(inst->flags, NACL_IFLAG(NaClIllegal))) {
429 gprintf(file, "(illegal)");
430 }
431 } else {
432 NaClPrintLower(file, (char*) NaClMnemonicName(inst->name));
433 }
434
435 /* Use the generated expression tree to print out (non-implicit) operands
436 * of the instruction.
437 */
438 while (tree_index < vector->number_expr_nodes) {
439 node = &vector->node[tree_index];
440 if (node->kind != OperandReference ||
441 (NACL_EMPTY_EFLAGS == (node->flags & NACL_EFLAG(ExprImplicit)))) {
442 if (is_first) {
443 gprintf(file, " ");
444 is_first = FALSE;
445 } else {
446 gprintf(file, ", ");
447 }
448 NaClPrintDisassembledExp(file, state, tree_index);
449
450 /* If this is a partial instruction, add set/use information
451 * so that that it is more clear what was matched.
452 */
453 if (NaClHasBit(inst->flags, NACL_IFLAG(PartialInstruction)) &&
454 node->kind == OperandReference) {
455 const NaClOp* op =
456 NaClGetInstOperandInline(state->decoder_tables,
457 inst,
458 (uint8_t) NaClGetExprUnsignedValue(node));
459 if (NaClHasBit(op->flags, (NACL_OPFLAG(OpSet) |
460 NACL_OPFLAG(OpUse) |
461 NACL_OPFLAG(OperandZeroExtends_v)))) {
462 gprintf(file, " (");
463 NaClPrintAddOperandFlag(file, op, OpSet, "s");
464 NaClPrintAddOperandFlag(file, op, OpUse, "u");
465 NaClPrintAddOperandFlag(file, op, OperandZeroExtends_v, "z");
466 gprintf(file, ")");
467 }
468 }
469 } else if (not_printed_prefix_segment &&
470 (OperandReference == node->kind) &&
471 (node->flags & NACL_EFLAG(ExprImplicit))) {
472 /* Print out segment override of implicit segment address, if
473 * applicable.
474 */
475 if (OperandReference == node->kind) {
476 int seg_addr_index = tree_index + 1;
477 if (ExprSegmentAddress == vector->node[seg_addr_index].kind) {
478 if (NaClHasSegmentOverride(vector, seg_addr_index,
479 ExprDSrCase, RegDS)) {
480 NaClPrintSegmentOverride(file, &is_first, state, vector,
481 seg_addr_index);
482 } else if (NaClHasSegmentOverride(vector, seg_addr_index,
483 ExprESrCase, RegES)) {
484 NaClPrintSegmentOverride(file, &is_first, state, vector,
485 seg_addr_index);
486 }
487 }
488 }
489 }
490 /* Skip over expression to next expresssion. */
491 tree_index += NaClExpWidth(vector, tree_index);
492 }
493 }
494
495 void NaClInstStateInstPrint(struct Gio* file, NaClInstState* state) {
496 int i;
497 const NaClInst* inst;
498
499 /* Print out the address and the inst bytes. */
500 int length = NaClInstStateLength(state);
501
502 DEBUG_OR_ERASE(
503 NaClInstPrint(file, state->decoder_tables, NaClInstStateInst(state)));
504 DEBUG(NaClExpVectorPrint(file, state));
505 gprintf(file, "%"NACL_PRIxNaClPcAddressAll": ",
506 NaClInstStatePrintableAddress(state));
507 for (i = 0; i < length; ++i) {
508 gprintf(file, "%02"NACL_PRIx8" ", NaClInstStateByte(state, i));
509 }
510 for (i = length; i < NACL_MAX_BYTES_PER_X86_INSTRUCTION; ++i) {
511 gprintf(file, " ");
512 }
513
514 /* Print out the assembly instruction it disassembles to. */
515 inst = NaClInstStateInst(state);
516 NaClPrintDisassembled(file, state, inst);
517 gprintf(file, "\n");
518 }
519
520 /* Defines a buffer size big enough to hold an instruction. */
521 #define MAX_INST_TEXT_SIZE 256
522
523 char* NaClInstStateInstructionToString(struct NaClInstState* state) {
524 /* Print to a memory buffer, and then duplicate. */
525 struct GioMemoryFile filemem;
526 struct Gio *file = (struct Gio*) &filemem;
527 char buffer[MAX_INST_TEXT_SIZE];
528 char* result;
529
530 /* Note: Be sure to leave an extra byte to add the null character to
531 * the end of the string.
532 */
533 GioMemoryFileCtor(&filemem, buffer, MAX_INST_TEXT_SIZE - 1);
534 NaClInstStateInstPrint(file, state);
535 buffer[filemem.curpos < MAX_INST_TEXT_SIZE
536 ? filemem.curpos : MAX_INST_TEXT_SIZE] ='\0';
537 result = strdup(buffer);
538 GioMemoryFileDtor(file);
539 return result;
540 }
541
542 int NaClExpWidth(NaClExpVector* vector, int node) {
543 int i;
544 int count = 1;
545 int num_kids = NaClExpKindRank(vector->node[node].kind);
546 for (i = 0; i < num_kids; i++) {
547 count += NaClExpWidth(vector, node + count);
548 }
549 return count;
550 }
551
552 int NaClGetExpKidIndex(NaClExpVector* vector, int node, int kid) {
553 node++;
554 while (kid-- > 0) {
555 node += NaClExpWidth(vector, node);
556 }
557 return node;
558 }
559
560 int NaClGetExpParentIndex(NaClExpVector* vector, int index) {
561 int node_rank;
562 int num_kids = 1;
563 while (index > 0) {
564 --index;
565 node_rank = NaClExpKindRank(vector->node[index].kind);
566 if (node_rank >= num_kids) {
567 return index;
568 } else {
569 num_kids -= (node_rank - 1);
570 }
571 }
572 return -1;
573 }
574
575 int NaClGetNthExpKind(NaClExpVector* vector,
576 NaClExpKind kind,
577 int n) {
578 if (n > 0) {
579 uint32_t i;
580 for (i = 0; i < vector->number_expr_nodes; ++i) {
581 if (kind == vector->node[i].kind) {
582 --n;
583 if (n == 0) return i;
584 }
585 }
586 }
587 return -1;
588 }
589
590 Bool NaClIsExpNegativeConstant(NaClExpVector* vector, int index) {
591 NaClExp* node = &vector->node[index];
592 switch (node->kind) {
593 case ExprConstant:
594 if (node->flags & NACL_EFLAG(ExprUnsignedHex) ||
595 node->flags & NACL_EFLAG(ExprUnsignedInt)) {
596 return FALSE;
597 } else {
598 /* Assume signed value. */
599 return NaClGetExprSignedValue(node) < 0;
600 }
601 break;
602 default:
603 break;
604 }
605 return FALSE;
606 }
607
608 /* Dummy routine to allow unreferenced NaClGetInstNumberOperandsInline
609 * inline.
610 */
611 uint8_t NaClNcopExpsDummyNaClGetInstNumberOperands(const NaClInst* inst) {
612 return NaClGetInstNumberOperandsInline(inst);
613 }
OLDNEW
« no previous file with comments | « src/trusted/validator/x86/decoder/ncop_exps.h ('k') | src/trusted/validator/x86/decoder/ncop_exps_inl.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698