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

Side by Side Diff: src/trusted/validator_ragel/gen-decoder.C

Issue 9348082: Move unreviewed files to unreviewed subdirectory (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client/
Patch Set: Created 8 years, 10 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 <fcntl.h>
8 #include <getopt.h>
9 #include <libgen.h>
10 #include <libintl.h>
11 #include <locale.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include <algorithm>
17 #include <map>
18 #include <set>
19 #include <string>
20 #include <tuple>
21 #include <vector>
22
23 template <typename T, size_t N>
24 char (&ArraySizeHelper(T (&array)[N]))[N];
25 #define arraysize(array) (sizeof(ArraySizeHelper(array)))
26
27 char* _(const char *s) { return gettext(s); }
28 const char* N_(const char *s) { return s; }
29
30 namespace {
31 const char* short_program_name;
32
33 const struct option kProgramOptions[] = {
34 {"mode", required_argument, NULL, 'm'},
35 {"disable", required_argument, NULL, 'd'},
36 {"output", required_argument, NULL, 'o'},
37 {"help", no_argument, NULL, 'h'},
38 {"version", no_argument, NULL, 'v'},
39 {NULL, 0, NULL, 0}
40 };
41
42 const char kVersion[] = "0.0";
43
44 const char*const kProgramHelp = N_("Usage: %1$s [OPTION]… FILES…\n"
45 "\n"
46 "Creates ragel machine which recognizes instructions listed in given files.\n"
47 "\n"
48 "Mandatory arguments to long options are mandatory for short options too.\n"
49 "\n"
50 "Options list:\n"
51 " -m, --mode=mode CPU mode: ia32 for IA32, amd64 for x86-64\n"
52 " -d, --disable=action_list disable actions from the comma-separated list\n"
53 " -o, --output=FILE write result to FILE instead of standard output\n"
54 " -h, --help display this help and exit\n"
55 " -v, --version output version information and exit\n"
56 "\n"
57 "Here is the full list of possible action types with short descrion of places\n"
58 "where they are insered:\n"
59 " rex_prefix triggered when legacy REX prefix is parsed\n"
60 " @rex_prefix inserted after possible REX prefix\n"
61 " vex_prefix triggered when VEX-encoded action is detected\n"
62 " @vex_prefix2 inserted after second byte of three-byte VEX/XOP prefi x\n"
63 " @vex_prefix3 inserted after third byte of three-byte VEX/XOP prefix \n"
64 " @vex_prefix_short inserted after second byte of two-byte VEX prefix\n"
65 " Note: there are no “vex_prefix1” because first byte of\n "
66 " VEX/XOP encoding is multiplexed to “lds”, “les” or\n"
67 " “pop Eq” instruction\n"
68 " instruction_name triggered when we have processed enough bytes to know th e\n"
69 " name of instruction\n"
70 " @instruction_NAME inserted when NAME is known.\n"
71 " Note: if this action is enabled then a set of actions\n"
72 " will be generated, not just a single call of single\n"
73 " action\n"
74 " opcode this will generate opcode actions\n"
75 " >opcode_begin inserted where actual opcode is started (without any\n "
76 " possible prefixes)\n"
77 " @opcode_end inserted where actual opcode is parsed\n"
78 " Note: some instructions use dedicated prefixes (0x66,\n"
79 " 0xf2, 0xf3) or immediate byte (“cmpeqpd”, “pf2id”,\n"
80 " etc) to distinguish operands—these are not captured\n"
81 " between “>opcode_begin” and “@opcode_end”\n"
82 " parse_operands this will grab instruction operands\n"
83 " mark_data_fields this will make “data fields” (dispXX, immXX, relXX) with \n"
84 " xxxXX_operand_begin and xxxXX_operand_end\n"
85 " check_access this will check memory access (actions is not generated\ n"
86 " by %1$s, you need to define it in your program)\n"
87 "\n"
88 " imm_operand_action generate imm_operand action references, but not actions\ n"
89 " themselves - in you need non-standard definition\n"
90 "\n"
91 " rel_operand_action generate rel_operand action references, but not actions\ n"
92 " themselves - in you need non-standard definition\n"
93 "\n"
94 " nacl-forbidden don't generate instructions forbidden for nacl\n");
95
96 const char*const kVersionHelp = N_("%1$s %2$s\n"
97 "Copyright (c) 2012 The Native Client Authors. All rights reserved.\n"
98 "Use of this source code is governed by a BSD-style license that can be\n"
99 "found in the LICENSE file.\n"
100 "");
101
102 enum class Actions {
103 kRexPrefix,
104 kVexPrefix,
105 kInstructionName,
106 kOpcode,
107 kParseOperands,
108 kParseOperandsStates,
109 kMarkDataFields,
110 kCheckAccess,
111 kImmOperandAction,
112 kRelOperandAction,
113 kNaClForbidden
114 };
115 const char* kDisablableActionsList[] = {
116 "rex_prefix",
117 "vex_prefix",
118 "instruction_name",
119 "opcode",
120 "parse_operands",
121 "parse_operands_states",
122 "mark_data_fields",
123 "check_access",
124 "imm_operand_action",
125 "rel_operand_action",
126 "nacl-forbidden"
127 };
128 bool disabled_actions[arraysize(kDisablableActionsList)];
129
130 bool enabled(Actions action) {
131 return !disabled_actions[static_cast<int>(action)];
132 }
133
134 std::map<std::string, size_t> instruction_names;
135 struct Instruction {
136 std::string name;
137 struct Operand {
138 char source;
139 std::string size;
140 bool read;
141 bool write;
142 bool implicit;
143 };
144 std::vector<Operand> operands;
145 std::vector<std::string> opcodes;
146 #if 0
147 /* We need GCC 4.7 for the following */
148 #define INSTRUCTION_FLAG(x) bool x :1 = false;
149 #else
150 /* Use this and “Instruction instruction { }”… */
151 #define INSTRUCTION_FLAG(x) bool x :1;
152 #endif
153 #include "gen-decoder-flags.C"
154 #undef INSTRUCTION_FLAG
155 };
156 std::vector<Instruction> instructions;
157
158 FILE *out_file = stdout;
159 FILE *const_file = stdout;
160 char *out_file_name = NULL;
161
162 auto ia32_mode = true;
163
164 std::string read_file(const char *filename) {
165 std::string file_content;
166 auto file = open(filename, O_RDONLY);
167 char buf[1024];
168 ssize_t count;
169
170 if (file == -1) {
171 fprintf(stderr, _("%s: can not open “%s” file (%s)\n"),
172 short_program_name, filename, strerror(errno));
173 exit(1);
174 }
175 while ((count = read(file, buf, sizeof(buf))) > 0) {
176 for (auto it = buf; it < buf + count ; ++it) {
177 if (*it != '\r') {
178 file_content.push_back(*it);
179 } else {
180 file_content.push_back('\n');
181 }
182 }
183 }
184 if (count == -1) {
185 fprintf(stderr, _("%s: can not read “%s” file (%s)\n"),
186 short_program_name, filename, strerror(errno));
187 exit(1);
188 }
189 if (close(file)) {
190 fprintf(stderr, _("%s: can not close “%s” file (%s)\n"),
191 short_program_name, filename, strerror(errno));
192 exit(1);
193 }
194 return file_content;
195 }
196
197 bool eol(char c) {
198 return c == '\n';
199 }
200
201 bool right_parenthesis(char c) {
202 return c == ')';
203 }
204
205 bool whitespace(char c) {
206 return c == ' ' || c == '\t';
207 }
208
209 std::vector<std::string> get_strings(std::string::const_iterator &it,
210 std::string::const_iterator end) {
211 std::vector<std::string> strings;
212 std::string string;
213 while ((it = std::find_if_not(it, end, whitespace)) < end && *it != ',') {
214 for (; it < end && *it != ',' && !whitespace(*it); ++it) {
215 if (*it != '\\') {
216 string.push_back(*it);
217 } else {
218 if (*++it == '(') {
219 auto parenthesis = std::find_if(it, end, right_parenthesis);
220 string.insert(string.end(), it, ++parenthesis);
221 it = --parenthesis;
222 } else {
223 string.push_back(*it);
224 }
225 }
226 }
227 strings.push_back(string);
228 string.clear();
229 }
230 return strings;
231 }
232
233 struct extract_operand {
234 Instruction &instruction;
235 std::vector<std::string> &operation;
236
237 extract_operand(Instruction &i, std::vector<std::string> &o)
238 : instruction(i), operation(o) {
239 }
240
241 void operator()(std::string &str) {
242 Instruction::Operand operand;
243 switch (str[0]) {
244 case '\'':
245 operand = {str[1], str.substr(2), false, false, false};
246 break;
247 case '=':
248 operand = {str[1], str.substr(2), true, false, false};
249 break;
250 case '!':
251 operand = {str[1], str.substr(2), false, true, false};
252 break;
253 case '&':
254 operand = {str[1], str.substr(2), true, true, false};
255 break;
256 default:
257 if (&str == &*operation.rbegin()) {
258 if (operation.size() <= 3) {
259 operand = {str[0], str.substr(1), true, true, false};
260 } else {
261 operand = {str[0], str.substr(1), false, true, false};
262 }
263 } else {
264 operand = {str[0], str.substr(1), true, false, false};
265 }
266 }
267 if (*(operand.size.rbegin()) == '*') {
268 operand.size.resize(operand.size.length() - 1);
269 }
270 instruction.operands.push_back(operand);
271 }
272 };
273
274 void load_instructions(const char *filename) {
275 const auto file_content = read_file(filename);
276 auto it = file_content.begin();
277 while (it != file_content.end()) {
278 it = std::find_if_not(it, file_content.end(), eol);
279 if (it == file_content.end()) {
280 return;
281 }
282 /* If line starts with “#” then it's a comment. */
283 if (*it == '#') {
284 it = std::find_if(it, file_content.end(), eol);
285 } else {
286 auto end = std::find_if(it, file_content.end(), eol);
287 /* Note: initialization list makes sure flags are toggled to zero. */
288 Instruction instruction { };
289 auto operation = get_strings(it, end);
290 /* Line with just a whitespaces is ignored. */
291 if (operation.size() != 0) {
292 instruction_names[instruction.name = operation[0]] = 0;
293 for_each(operation.rbegin(), operation.rend() - 1,
294 extract_operand(instruction, operation));
295 auto enabled_instruction = true;
296 if (*it == ',') {
297 ++it;
298 instruction.opcodes = get_strings(it, end);
299 if (*it == ',') {
300 ++it;
301 auto flags = get_strings(it, end);
302 for (auto flag_it = flags.begin(); flag_it != flags.end(); ++flag_ it) {
303 auto &flag = *flag_it;
304 #define INSTRUCTION_FLAG(x) \
305 if (flag == #x) {instruction.x = true;} else
306 #include "gen-decoder-flags.C"
307 #undef INSTRUCTION_FLAG
308 if (flag == "ia32") {
309 if (!ia32_mode) {
310 enabled_instruction = false;
311 break;
312 }
313 } else if (flag == "amd64") {
314 if (ia32_mode) {
315 enabled_instruction = false;
316 break;
317 }
318 } else if (flag == "nacl-ia32-forbidden") {
319 if (ia32_mode && !enabled(Actions::kNaClForbidden)) {
320 enabled_instruction = false;
321 break;
322 }
323 } else if (flag == "nacl-amd64-forbidden") {
324 if (!ia32_mode && !enabled(Actions::kNaClForbidden)) {
325 enabled_instruction = false;
326 break;
327 }
328 } else if (flag == "nacl-forbidden") {
329 if (!enabled(Actions::kNaClForbidden)) {
330 enabled_instruction = false;
331 break;
332 }
333 } else {
334 fprintf(stderr, _("%s: unknown flag: “%s”\n"),
335 short_program_name, flag.c_str());
336 exit(1);
337 }
338 }
339 }
340 }
341 if (enabled_instruction) {
342 instructions.push_back(instruction);
343 }
344 }
345 it = std::find_if(it, file_content.end(), eol);
346 }
347 }
348 }
349
350 #if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 6)
351 #define USE_LAMBDA_IN_CHARTEST 1
352 #else
353 #define USE_LAMBDA_IN_CHARTEST 0
354 #endif
355 #if USE_LAMBDA_IN_CHARTEST
356 template<typename func>
357 std::string chartest(func f) {
358 #else
359 std::string chartest(std::vector<bool> v) {
360 #endif
361 std::string result;
362 auto delimeter = "( ";
363 for (int c = 0x00; c <= 0xff; ++c) {
364 #if USE_LAMBDA_IN_CHARTEST
365 if (f(c)) {
366 #else
367 if (v[c]) {
368 #endif
369 char buf[10];
370 sprintf(buf, "%s0x%02x", delimeter, c);
371 result += buf;
372 delimeter = " | ";
373 }
374 }
375 return result + " )";
376 }
377 #if USE_LAMBDA_IN_CHARTEST
378 #define chartest(x) (chartest([=](int c) { return x; }).c_str())
379 #else
380 struct comparator {
381 const std::vector<bool> &v;
382 const int n;
383 comparator(const std::vector<bool> &v_, const int n_) : v(v_), n(n_) { }
384 #define operator(x) \
385 const std::vector<bool> operator x (int m) { \
386 std::vector<bool> r(256, false); \
387 for (int c = 0x00; c <= 0xff; ++c) { \
388 if (v[c]) { \
389 r[c] = (c & n) x m; \
390 } \
391 } \
392 return r; \
393 }
394 operator(==)
395 operator(!=)
396 operator(<=)
397 operator(>=)
398 operator(<)
399 operator(>)
400 #undef operator
401 };
402 comparator operator& (const std::vector<bool> &v, int n) {
403 return comparator(v, n);
404 }
405 #define operator(x) \
406 const std::vector<bool> operator x (const std::vector<bool> &v1, \
407 const std::vector<bool> &v2) { \
408 std::vector<bool> r(256); \
409 for (int c = 0x00; c <= 0xff; ++c) { \
410 r[c] = (v1[c] x v2[c]); \
411 } \
412 return r; \
413 }
414 operator(&&)
415 operator(||)
416 #undef operator
417 #define chartest(x) (chartest(x).c_str())
418 std::vector<bool> c(256, true);
419 #endif
420
421 const std::string& select_name(std::map<std::string, size_t>::value_type& p) {
422 return p.first;
423 }
424
425 bool compare_names(const std::string& x, const std::string& y) {
426 return (x.size() > y.size()) || ((x.size() == y.size()) && x < y);
427 }
428
429 void print_consts(void) {
430 if (enabled(Actions::kInstructionName)) {
431 std::vector<std::string> names;
432 std::transform(instruction_names.begin(), instruction_names.end(),
433 std::back_inserter(names),
434 select_name);
435 std::sort(names.begin(), names.end(), compare_names);
436 for (auto name_it = names.begin(); name_it != names.end(); ++name_it) {
437 auto &name = *name_it;
438 if (instruction_names[name] == 0) {
439 for (decltype(name.length()) p = 1; p < name.length(); ++p) {
440 auto it = instruction_names.find(std::string(name, p));
441 if (it != instruction_names.end()) {
442 it->second = 1;
443 }
444 }
445 }
446 }
447 size_t offset = 0;
448 for (auto pair_it = instruction_names.begin(); pair_it != instruction_name s.end(); ++pair_it) {
449 auto &pair = *pair_it;
450 if (pair.second != 1) {
451 pair.second = offset;
452 offset += pair.first.length() + 1;
453 }
454 }
455 for (auto name_it = names.begin(); name_it != names.end(); ++name_it) {
456 auto &name = *name_it;
457 auto offset = instruction_names[name];
458 if (offset != 1) {
459 for (decltype(name.length()) p = 1; p < name.length(); ++p) {
460 auto it = instruction_names.find(std::string(name, p));
461 if ((it != instruction_names.end()) && (it->second == 1)) {
462 it->second = offset + p;
463 }
464 }
465 }
466 }
467 offset = 0;
468 auto delimeter = "static const char instruction_names[] = {\n ";
469 for (auto pair_it = instruction_names.begin(); pair_it != instruction_name s.end(); ++pair_it) {
470 auto &pair = *pair_it;
471 if (pair.second == offset) {
472 fprintf(const_file, "%s", delimeter);
473 for (auto c_it = pair.first.begin(); c_it != pair.first.end(); ++c_it) {
474 auto &c = *c_it;
475 fprintf(const_file, "0x%02x, ", static_cast<int>(c));
476 }
477 fprintf(const_file, "\'\\0\', /* ");
478 fprintf(const_file, "%s", pair.first.c_str());
479 offset += pair.first.length() + 1;
480 delimeter = " */\n ";
481 }
482 }
483 fprintf(const_file, " */\n};\n");
484 }
485 if (enabled(Actions::kParseOperands)) {
486 fprintf(const_file, "static const uint8_t index_registers[] = {\n"
487 " REG_RAX, REG_RCX, REG_RDX, REG_RBX,\n"
488 " REG_RIZ, REG_RBP, REG_RSI, REG_RDI,\n"
489 " REG_R8, REG_R9, REG_R10, REG_R11,\n"
490 " REG_R12, REG_R13, REG_R14, REG_R15\n"
491 "};\n"
492 "");
493 }
494 }
495
496 std::string c_identifier(std::string text) {
497 std::string name;
498 for (auto c_it = text.begin(); c_it != text.end(); ++c_it) {
499 auto c = *c_it;
500 if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') ||
501 ('0' <= c && c <= '9')) {
502 name.push_back(c);
503 } else {
504 name.push_back('_');
505 }
506 }
507 return name;
508 }
509
510 void print_common_decoding(void) {
511 if (enabled(Actions::kRelOperandAction)) {
512 fprintf(out_file, " action rel8_operand {\n"
513 " operand0 = JMP_TO;\n"
514 " base = REG_RIP;\n"
515 " index = REG_NONE;\n"
516 " scale = 0;\n"
517 " disp_type = DISP8;\n"
518 " disp = p;\n"
519 " }\n"
520 " action rel16_operand {\n"
521 " operand0 = JMP_TO;\n"
522 " base = REG_RIP;\n"
523 " index = REG_NONE;\n"
524 " scale = 0;\n"
525 " disp_type = DISP16;\n"
526 " disp = p - 1;\n"
527 " }\n"
528 " action rel32_operand {\n"
529 " operand0 = JMP_TO;\n"
530 " base = REG_RIP;\n"
531 " index = REG_NONE;\n"
532 " scale = 0;\n"
533 " disp_type = DISP32;\n"
534 " disp = p - 3;\n"
535 " }\n"
536 "");
537 }
538 fprintf(out_file, " action branch_not_taken {\n"
539 " branch_taken = TRUE;\n"
540 " }\n"
541 " action branch_taken {\n"
542 " branch_taken = TRUE;\n"
543 " }\n"
544 " action data16_prefix {\n"
545 " data16_prefix = TRUE;\n"
546 " }\n"
547 " action lock_prefix {\n"
548 " lock_prefix = TRUE;\n"
549 " }\n"
550 " action rep_prefix {\n"
551 " repz_prefix = TRUE;\n"
552 " }\n"
553 " action repz_prefix {\n"
554 " repz_prefix = TRUE;\n"
555 " }\n"
556 " action repnz_prefix {\n"
557 " repnz_prefix = TRUE;\n"
558 " }\n"
559 " action not_data16_prefix {\n"
560 " data16_prefix = FALSE;\n"
561 " }\n"
562 " action not_lock_prefix0 {\n"
563 " operand0 |= 0x08;\n"
564 " lock_prefix = FALSE;\n"
565 " }\n"
566 " action not_lock_prefix1 {\n"
567 " operand1 |= 0x08;\n"
568 " lock_prefix = FALSE;\n"
569 " }\n"
570 " action not_repnz_prefix {\n"
571 " repnz_prefix = FALSE;\n"
572 " }\n"
573 " action not_repz_prefix {\n"
574 " repz_prefix = FALSE;\n"
575 " }\n"
576 " action disp8_operand {\n"
577 " disp_type = DISP8;\n"
578 " disp = p;\n"
579 " }\n"
580 " action disp32_operand {\n"
581 " disp_type = DISP32;\n"
582 " disp = p - 3;\n"
583 " }\n"
584 " action disp64_operand {\n"
585 " disp_type = DISP64;\n"
586 " disp = p - 7;\n"
587 " }\n");
588 if (enabled(Actions::kImmOperandAction)) {
589 fprintf(out_file, " action imm2_operand {\n"
590 " imm_operand = IMM2;\n"
591 " imm = p;\n"
592 " }\n"
593 " action imm8_operand {\n"
594 " imm_operand = IMM8;\n"
595 " imm = p;\n"
596 " }\n"
597 " action imm8_second_operand {\n"
598 " imm2_operand = IMM8;\n"
599 " imm2 = p;\n"
600 " }\n"
601 " action imm16_operand {\n"
602 " imm_operand = IMM16;\n"
603 " imm = p - 1;\n"
604 " }\n"
605 " action imm16_second_operand {\n"
606 " imm2_operand = IMM16;\n"
607 " imm2 = p - 1;\n"
608 " }\n"
609 " action imm32_operand {\n"
610 " imm_operand = IMM32;\n"
611 " imm = p - 3;\n"
612 " }\n"
613 " action imm32_second_operand {\n"
614 " imm2_operand = IMM32;\n"
615 " imm2 = p - 3;\n"
616 " }\n"
617 " action imm64_operand {\n"
618 " imm_operand = IMM64;\n"
619 " imm = p - 7;\n"
620 " }\n"
621 " action imm64_second_operand {\n"
622 " imm2_operand = IMM64;\n"
623 " imm2 = p - 7;\n"
624 " }\n"
625 "");
626 }
627 if (enabled(Actions::kParseOperands)) {
628 if (ia32_mode) {
629 fprintf(out_file, " action modrm_only_base {\n"
630 " disp_type = DISPNONE;\n"
631 " index = REG_NONE;\n"
632 " base = (*p) & 0x07;\n"
633 " scale = 0;\n"
634 " }\n"
635 " action modrm_base_disp {\n"
636 " index = REG_NONE;\n"
637 " base = (*p) & 0x07;\n"
638 " scale = 0;\n"
639 " }\n"
640 " action modrm_pure_disp {\n"
641 " base = REG_NONE;\n"
642 " index = REG_NONE;\n"
643 " scale = 0;\n"
644 " }\n"
645 " action modrm_pure_index {\n"
646 " disp_type = DISPNONE;\n"
647 " base = REG_NONE;\n"
648 " index = index_registers[((*p) & 0x38) >> 3];\n"
649 " scale = ((*p) & 0xc0) >> 6;\n"
650 " }\n"
651 " action modrm_parse_sib {\n"
652 " disp_type = DISPNONE;\n"
653 " base = (*p) & 0x7;\n"
654 " index = index_registers[((*p) & 0x38) >> 3];\n"
655 " scale = ((*p) & 0xc0) >> 6;\n"
656 " }\n");
657 } else {
658 fprintf(out_file, " action modrm_only_base {\n"
659 " disp_type = DISPNONE;\n"
660 " index = REG_NONE;\n"
661 " base = ((*p) & 0x07) |\n"
662 " ((rex_prefix & 0x01) << 3) |\n"
663 " (((~vex_prefix2) & 0x20) >> 2);\n"
664 " scale = 0;\n"
665 " }\n"
666 " action modrm_base_disp {\n"
667 " index = REG_NONE;\n"
668 " base = ((*p) & 0x07) |\n"
669 " ((rex_prefix & 0x01) << 3) |\n"
670 " (((~vex_prefix2) & 0x20) >> 2);\n"
671 " scale = 0;\n"
672 " }\n"
673 " action modrm_rip {\n"
674 " index = REG_NONE;\n"
675 " base = REG_RIP;\n"
676 " scale = 0;\n"
677 " }\n"
678 " action modrm_pure_index {\n"
679 " disp_type = DISPNONE;\n"
680 " base = REG_NONE;\n"
681 " index = index_registers[(((*p) & 0x38) >> 3) |\n"
682 " ((rex_prefix & 0x02) << 2) |\n"
683 " (((~vex_prefix2) & 0x40) >> 3)];\n"
684 " scale = ((*p) & 0xc0) >> 6;\n"
685 " }\n"
686 " action modrm_parse_sib {\n"
687 " disp_type = DISPNONE;\n"
688 " base = ((*p) & 0x7) |\n"
689 " ((rex_prefix & 0x01) << 3) |\n"
690 " (((~vex_prefix2) & 0x20) >> 2);\n"
691 " index = index_registers[(((*p) & 0x38) >> 3) |\n"
692 " ((rex_prefix & 0x02) << 2) |\n"
693 " (((~vex_prefix2) & 0x40) >> 3)];\n"
694 " scale = ((*p) & 0xc0) >> 6;\n"
695 " }\n"
696 "");
697 }
698 }
699 fprintf(out_file, "\n"
700 " # Relative jumps and calls.\n"
701 " rel8 = any %s;\n"
702 " rel16 = any{2} %s;\n"
703 " rel32 = any{4} %s;\n"
704 "", enabled(Actions::kMarkDataFields) ?
705 ">rel8_operand_begin @rel8_operand_end" : "@rel8_operand",
706 enabled(Actions::kMarkDataFields) ?
707 ">rel16_operand_begin @rel16_operand_end" : "@rel16_operand",
708 enabled(Actions::kMarkDataFields) ?
709 ">rel32_operand_begin @rel32_operand_end" : "@rel32_operand");
710 fprintf(out_file, "\n"
711 " # Displacements.\n"
712 " disp8 = any %s;\n"
713 " disp32 = any{4} %s;\n"
714 " disp64 = any{8} %s;\n"
715 "", enabled(Actions::kMarkDataFields) ?
716 ">disp8_operand_begin @disp8_operand_end" : "@disp8_operand",
717 enabled(Actions::kMarkDataFields) ?
718 ">disp32_operand_begin @disp32_operand_end" : "@disp32_operand",
719 enabled(Actions::kMarkDataFields) ?
720 ">disp64_operand_begin @disp64_operand_end" : "@disp64_operand");
721 fprintf(out_file, "\n"
722 " # Immediates.\n"
723 " imm2 = %s @imm2_operand;\n"
724 "", ia32_mode ? chartest((c & 0x8c) == 0x00) : chartest((c & 0x0c) == 0x00));
725 fprintf(out_file, " imm8 = any %s;\n"
726 " imm16 = any{2} %s;\n"
727 " imm32 = any{4} %s;\n"
728 " imm64 = any{8} %s;\n"
729 " imm8n2 = any %s;\n"
730 " imm16n2 = any{2} %s;\n"
731 " imm32n2 = any{4} %s;\n"
732 " imm64n2 = any{8} %s;\n"
733 "", enabled(Actions::kMarkDataFields) ?
734 ">imm8_operand_begin @imm8_operand_end" : "@imm8_operand",
735 enabled(Actions::kMarkDataFields) ?
736 ">imm8_operand_begin @imm16_operand_end" : "@imm16_operand",
737 enabled(Actions::kMarkDataFields) ?
738 ">imm8_operand_begin @imm32_operand_end" : "@imm32_operand",
739 enabled(Actions::kMarkDataFields) ?
740 ">imm8_operand_begin @imm64_operand_end" : "@imm64_operand",
741 enabled(Actions::kMarkDataFields) ?
742 ">imm8_operand_begin @imm8_operand_end" : "@imm8_second_operand",
743 enabled(Actions::kMarkDataFields) ?
744 ">imm16_operand_begin @imm16_operand_end" : "@imm16_second_operand",
745 enabled(Actions::kMarkDataFields) ?
746 ">imm32_operand_begin @imm32_operand_end" : "@imm32_second_operand",
747 enabled(Actions::kMarkDataFields) ?
748 ">imm64_operand_begin @imm64_operand_end" : "@imm64_second_operand");
749 fprintf(out_file, "\n"
750 " # Different types of operands.\n"
751 " operand_sib_base_index = (%2$s . %3$s%1$s) |\n"
752 " (%4$s . any%1$s . disp8) |\n"
753 " (%5$s . any%1$s . disp32);\n"
754 "", enabled(Actions::kParseOperands) ? " @modrm_parse_sib" : "",
755 chartest((c & 0xC0) == 0 && (c & 0x07) == 0x04),
756 chartest((c & 0x07) != 0x05),
757 chartest((c & 0xC0) == 0x40 && (c & 0x07) == 0x04),
758 chartest((c & 0xC0) == 0x80 && (c & 0x07) == 0x04));
759 fprintf(out_file, " operand_sib_pure_index = %2$s . %3$s%1$s . disp32;\n"
760 "", enabled(Actions::kParseOperands) ? " @modrm_pure_index" : "",
761 chartest((c & 0xC0) == 0 && (c & 0x07) == 0x04),
762 chartest((c & 0x07) == 0x05));
763 fprintf(out_file, " operand_disp = (%2$s%1$s . disp8) |\n"
764 " (%3$s%1$s . disp32);\n"
765 "", enabled(Actions::kParseOperands) ? " @modrm_base_disp" : "",
766 chartest((c & 0xC0) == 0x40 && (c & 0x07) != 0x04),
767 chartest((c & 0xC0) == 0x80 && (c & 0x07) != 0x04));
768 fprintf(out_file, " # It's pure disp32 in IA32 case, "
769 "but offset(%%rip) in x86-64 case.\n"
770 " operand_rip = %2$s%1$s . disp32;\n"
771 "", enabled(Actions::kParseOperands) ?
772 ia32_mode ? " @modrm_pure_disp" : " @modrm_rip" : "",
773 chartest((c & 0xC0) == 0 && (c & 0x07) == 0x05));
774 fprintf(out_file, " single_register_memory = %2$s%1$s;\n"
775 "", enabled(Actions::kParseOperands) ? " @modrm_only_base" : "",
776 chartest((c & 0xC0) == 0 && (c & 0x07) != 0x04 &&
777 (c & 0x07) != 0x05));
778 fprintf(out_file, " modrm_memory = (operand_disp | operand_rip |\n"
779 " operand_sib_base_index | operand_sib_pure_index |\n"
780 " single_register_memory)%1$s;\n"
781 " modrm_registers = %2$s;\n"
782 "", enabled(Actions::kCheckAccess) ? " @check_access" : "",
783 chartest((c & 0xC0) == 0xC0));
784 fprintf(out_file, "\n"
785 " # Operations selected using opcode in ModR/M.\n"
786 " opcode_0 = %s;\n"
787 " opcode_1 = %s;\n"
788 " opcode_2 = %s;\n"
789 " opcode_3 = %s;\n"
790 " opcode_4 = %s;\n"
791 " opcode_5 = %s;\n"
792 " opcode_6 = %s;\n"
793 " opcode_7 = %s;\n"
794 " # Used for segment operations: there only 6 segment registers.\n"
795 " opcode_s = %s;\n"
796 " # This is used to move operand name detection after first byte of ModRM.\n"
797 " opcode_m = any;\n"
798 " opcode_r = any;\n"
799 "", chartest((c & 0x38) == 0x00),
800 chartest((c & 0x38) == 0x08),
801 chartest((c & 0x38) == 0x10),
802 chartest((c & 0x38) == 0x18),
803 chartest((c & 0x38) == 0x20),
804 chartest((c & 0x38) == 0x28),
805 chartest((c & 0x38) == 0x30),
806 chartest((c & 0x38) == 0x38),
807 chartest((c & 0x38) < 0x30));
808 fprintf(out_file, "\n"
809 " # Prefixes.\n"
810 " data16 = 0x66 @data16_prefix;\n"
811 " branch = 0x2e @branch_not_taken | 0x3e @branch_taken;\n"
812 " condrep = 0xf2 @repnz_prefix | 0xf3 @repz_prefix;\n"
813 " lock = 0xf0 @lock_prefix;\n"
814 " rep = 0xf3 @rep_prefix;\n"
815 " repnz = 0xf2 @repnz_prefix;\n"
816 " repz = 0xf3 @repz_prefix;\n"
817 "");
818 if (enabled(Actions::kRexPrefix)) {
819 fprintf(out_file, "\n"
820 " # REX prefixes.\n"
821 " action rex_prefix {\n"
822 " rex_prefix = *p;\n"
823 " }\n"
824 "");
825 }
826 fprintf(out_file, " REX_NONE = 0x40%1$s;\n"
827 " REX_W = %2$s%1$s;\n"
828 " REX_R = %3$s%1$s;\n"
829 " REX_X = %4$s%1$s;\n"
830 " REX_B = %5$s%1$s;\n"
831 " REX_WR = %6$s%1$s;\n"
832 " REX_WX = %7$s%1$s;\n"
833 " REX_WB = %8$s%1$s;\n"
834 " REX_RX = %9$s%1$s;\n"
835 " REX_RB = %10$s%1$s;\n"
836 " REX_XB = %11$s%1$s;\n"
837 " REX_WRX = %12$s%1$s;\n"
838 " REX_WRB = %13$s%1$s;\n"
839 " REX_WXB = %14$s%1$s;\n"
840 " REX_RXB = %15$s%1$s;\n"
841 " REX_WRXB = %16$s%1$s;\n"
842 "", enabled(Actions::kRexPrefix) ? " @rex_prefix" : "",
843 chartest((c & 0xf7) == 0x40),
844 chartest((c & 0xfb) == 0x40),
845 chartest((c & 0xfd) == 0x40),
846 chartest((c & 0xfe) == 0x40),
847 chartest((c & 0xf3) == 0x40),
848 chartest((c & 0xf5) == 0x40),
849 chartest((c & 0xf6) == 0x40),
850 chartest((c & 0xf9) == 0x40),
851 chartest((c & 0xfa) == 0x40),
852 chartest((c & 0xfc) == 0x40),
853 chartest((c & 0xf1) == 0x40),
854 chartest((c & 0xf2) == 0x40),
855 chartest((c & 0xf4) == 0x40),
856 chartest((c & 0xf8) == 0x40),
857 chartest((c & 0xf0) == 0x40));
858 fprintf(out_file, "\n"
859 " rex_w = REX_W - REX_NONE;\n"
860 " rex_r = REX_R - REX_NONE;\n"
861 " rex_x = REX_X - REX_NONE;\n"
862 " rex_b = REX_B - REX_NONE;\n"
863 " rex_wr = REX_WR - REX_NONE;\n"
864 " rex_wx = REX_WX - REX_NONE;\n"
865 " rex_wb = REX_WB - REX_NONE;\n"
866 " rex_rx = REX_RX - REX_NONE;\n"
867 " rex_rb = REX_RB - REX_NONE;\n"
868 " rex_xb = REX_XB - REX_NONE;\n"
869 " rex_wrx = REX_WRX - REX_NONE;\n"
870 " rex_wrb = REX_WRB - REX_NONE;\n"
871 " rex_wxb = REX_WXB - REX_NONE;\n"
872 " rex_rxb = REX_RXB - REX_NONE;\n"
873 " rex_wrxb = REX_WRXB - REX_NONE;\n"
874 " REXW_NONE= 0x48%1$s;\n"
875 " REXW_R = %2$s%1$s;\n"
876 " REXW_X = %3$s%1$s;\n"
877 " REXW_B = %4$s%1$s;\n"
878 " REXW_RX = %5$s%1$s;\n"
879 " REXW_RB = %6$s%1$s;\n"
880 " REXW_XB = %7$s%1$s;\n"
881 " REXW_RXB = %8$s%1$s;\n"
882 "", enabled(Actions::kRexPrefix) ? " @rex_prefix" : "",
883 chartest((c & 0xfb) == 0x48),
884 chartest((c & 0xfd) == 0x48),
885 chartest((c & 0xfe) == 0x48),
886 chartest((c & 0xf9) == 0x48),
887 chartest((c & 0xfa) == 0x48),
888 chartest((c & 0xfc) == 0x48),
889 chartest((c & 0xf8) == 0x48));
890 if (enabled(Actions::kVexPrefix)) {
891 if (ia32_mode) {
892 fprintf(out_file, "\n"
893 " # VEX/XOP prefix - byte 3.\n"
894 " action vex_prefix3 {\n"
895 " vex_prefix3 = *p;\n"
896 " }\n"
897 " # VEX/XOP short prefix\n"
898 " action vex_prefix_short {\n"
899 " /* VEX.R is not used in ia32 mode. */\n"
900 " vex_prefix3 = p[0] & 0x7f;\n"
901 " }\n"
902 "");
903 } else {
904 fprintf(out_file, "\n"
905 " # VEX/XOP prefix - byte 2.\n"
906 " action vex_prefix2 {\n"
907 " vex_prefix2 = *p;\n"
908 " }\n"
909 " # VEX/XOP prefix - byte 3.\n"
910 " action vex_prefix3 {\n"
911 " vex_prefix3 = *p;\n"
912 " }\n"
913 " # VEX/XOP short prefix\n"
914 " action vex_prefix_short {\n"
915 " /* This emulates two prefixes case. */\n"
916 " vex_prefix2 = (p[0] & 0x80) | 0x61;\n"
917 " vex_prefix3 = p[0] & 0x7f;\n"
918 " }\n"
919 "");
920 }
921 }
922 typedef std::pair<const char *, int> T;
923 static const T vex_fields[] = {
924 T { "NONE", 0xe0 },
925 T { "R", 0x60 },
926 T { "X", 0xa0 },
927 T { "B", 0xc0 },
928 T { "RX", 0x20 },
929 T { "RB", 0x40 },
930 T { "XB", 0x80 },
931 T { "RXB", 0x00 }
932 };
933 for (int vex_it = 0; vex_it < arraysize(vex_fields); ++vex_it) {
934 auto vex = vex_fields[vex_it];
935 fprintf(out_file, " VEX_%2$s = %3$s%1$s;\n"
936 "", enabled(Actions::kVexPrefix) && !ia32_mode ? " @vex_prefix2" : "",
937 vex.first, chartest((c & vex.second) == vex.second));
938 }
939 static const T vex_map[] = {
940 T { "01", 1 },
941 T { "02", 2 },
942 T { "03", 3 },
943 T { "08", 8 },
944 T { "09", 9 },
945 T { "0A", 10 },
946 T { "00001", 1 },
947 T { "00010", 2 },
948 T { "00011", 3 },
949 T { "01000", 8 },
950 T { "01001", 9 },
951 T { "01010", 10 },
952 };
953 for (int vex_it = 0; vex_it < arraysize(vex_map); ++vex_it) {
954 auto vex = vex_map[vex_it];
955 fprintf(out_file, " VEX_map%1$s = %2$s;\n"
956 "", vex.first, chartest((c & 0x1f) == vex.second));
957 }
958 if (enabled(Actions::kOpcode)) {
959 fprintf(out_file, "\n"
960 " action begin_opcode {\n"
961 " begin_opcode = p;\n"
962 " }\n"
963 " action end_opcode {\n"
964 " end_opcode = p;\n"
965 " }\n"
966 "");
967 }
968 if (enabled(Actions::kParseOperands)) {
969 for (auto i = 0 ; i <= 5; ++i) {
970 fprintf(out_file, " action operands_count_is_%1$d {\n"
971 " operands_count = %1$d;\n"
972 " }\n"
973 "", i);
974 }
975 for (auto i = 0 ; i < 5; ++i) {
976 typedef std::pair<const char *, const char *> T;
977 static const T sizes[] = {
978 T { "2bit", "Size2bit" },
979 T { "8bit", "Size8bit" },
980 T { "16bit", "Size16bit" },
981 T { "32bit", "Size32bit" },
982 T { "64bit", "Size64bit" },
983 T { "128bit", "Size128bit" },
984 T { "256bit", "Size256bit" },
985 T { "float16bit", "FloatSize16bit" },
986 T { "float32bit", "FloatSize32bit" },
987 T { "float64bit", "FloatSize64bit" },
988 T { "float80bit", "FloatSize80bit" },
989 T { "regsize", ia32_mode ? "Size32bit" :
990 "Size64bit" },
991 T { "x87_16bit", "X87Size16bit" },
992 T { "x87_32bit", "X87Size32bit" },
993 T { "x87_64bit", "X87Size64bit" },
994 T { "x87_bcd", "X87BCD" },
995 T { "x87_env", "X87ENV" },
996 T { "x87_state", "X87STATE" },
997 T { "x87_mmx_xmm_state", "X87MMXXMMSTATE" },
998 T { "x87", "ST" },
999 T { "mmx", "MMX" },
1000 T { "xmm", "XMM" },
1001 T { "ymm", "YMM" },
1002 T { "farptr", "FarPtr" },
1003 T { "segreg", "SegmentRegister" },
1004 T { "creg", "ControlRegister" },
1005 T { "dreg", "DebugRegister" },
1006 T { "selector", "Selector" }
1007 };
1008 for (int size_it = 0; size_it < arraysize(sizes); ++size_it) {
1009 auto size = sizes[size_it];
1010 fprintf(out_file, " action operand%1$d_%2$s {\n"
1011 " operand%1$d_type = Operand%3$s;\n"
1012 " }\n"
1013 "", i, size.first, size.second);
1014 }
1015 if (ia32_mode) {
1016 fprintf(out_file, " action operand%1$d_absolute_disp {\n"
1017 " operand%1$d = REG_RM;\n"
1018 " base = REG_NONE;\n"
1019 " index = REG_NONE;\n"
1020 " scale = 0;\n"
1021 " }\n"
1022 " action operand%1$d_from_opcode {\n"
1023 " operand%1$d = (*p) & 0x7;\n"
1024 " }\n"
1025 " action operand%1$d_from_is4 {\n"
1026 " operand%1$d = p[0] >> 4;\n"
1027 " }\n"
1028 " action operand%1$d_from_modrm_rm {\n"
1029 " operand%1$d = (*p) & 0x07;\n"
1030 " }\n"
1031 " action operand%1$d_from_modrm_reg {\n"
1032 " operand%1$d = ((*p) & 0x38) >> 3;\n"
1033 " }\n"
1034 " action operand%1$d_from_vex {\n"
1035 " operand%1$d = ((~vex_prefix3) & 0x38) >> 3;\n"
1036 " }\n"
1037 "", i);
1038 } else {
1039 fprintf(out_file, " action operand%1$d_absolute_disp {\n"
1040 " operand%1$d = REG_RM;\n"
1041 " base = REG_NONE;\n"
1042 " index = REG_RIZ;\n"
1043 " scale = 0;\n"
1044 " }\n"
1045 " action operand%1$d_from_opcode {\n"
1046 " operand%1$d = ((*p) & 0x7) |\n"
1047 " ((rex_prefix & 0x01) << 3) |\n"
1048 " (((~vex_prefix2) & 0x20) >> 2);\n"
1049 " }\n"
1050 " action operand%1$d_from_is4 {\n"
1051 " operand%1$d = p[0] >> 4;\n"
1052 " }\n"
1053 " action operand%1$d_from_modrm_rm {\n"
1054 " operand%1$d = ((*p) & 0x07) |\n"
1055 " ((rex_prefix & 0x01) << 3) |\n"
1056 " (((~vex_prefix2) & 0x20) >> 2);\n"
1057 " }\n"
1058 " action operand%1$d_from_modrm_reg {\n"
1059 " operand%1$d = (((*p) & 0x38) >> 3) |\n"
1060 " ((rex_prefix & 0x04) << 1) |\n"
1061 " (((~vex_prefix2) & 0x80) >> 4);\n"
1062 " }\n"
1063 " action operand%1$d_from_vex {\n"
1064 " operand%1$d = ((~vex_prefix3) & 0x78) >> 3;\n"
1065 " }\n"
1066 "", i);
1067 }
1068 static const T types[] = {
1069 T { "ds_rbx", "REG_DS_RBX" },
1070 T { "ds_rsi", "REG_DS_RSI" },
1071 T { "es_rdi", "REG_ES_RDI" },
1072 T { "immediate", "REG_IMM" },
1073 T { "second_immediate", "REG_IMM2" },
1074 T { "port_dx", "REG_PORT_DX" },
1075 T { "rax", "REG_RAX" },
1076 T { "rcx", "REG_RCX" },
1077 T { "rdx", "REG_RDX" },
1078 T { "rm", "REG_RM" },
1079 T { "st", "REG_ST" }
1080 };
1081 for (int type_it = 0; type_it < arraysize(types); ++type_it) {
1082 auto type = types[type_it];
1083 fprintf(out_file, " action operand%1$d_%2$s {\n"
1084 " operand%1$d = %3$s;\n"
1085 " }\n"
1086 "", i, type.first, type.second);
1087 }
1088 }
1089 }
1090 if (enabled(Actions::kParseOperandsStates)) {
1091 for (auto i = 0 ; i < 5; ++i) {
1092 fprintf(out_file, " action operand%1$d_unused {\n"
1093 " operand%1$d_read = false;\n"
1094 " operand%1$d_write = false;\n"
1095 " }\n"
1096 " action operand%1$d_read {\n"
1097 " operand%1$d_read = true;\n"
1098 " operand%1$d_write = false;\n"
1099 " }\n"
1100 " action operand%1$d_write {\n"
1101 " operand%1$d_read = false;\n"
1102 " operand%1$d_write = true;\n"
1103 " }\n"
1104 " action operand%1$d_readwrite {\n"
1105 " operand%1$d_read = true;\n"
1106 " operand%1$d_write = true;\n"
1107 " }\n"
1108 "", i);
1109 }
1110 }
1111 }
1112
1113 void print_name_actions(void) {
1114 for (auto pair_it = instruction_names.begin(); pair_it != instruction_names. end(); ++pair_it) {
1115 auto &pair = *pair_it;
1116 fprintf(out_file, " action instruction_%s"
1117 " { instruction_name = instruction_names + %zd; }\n",
1118 c_identifier(pair.first).c_str(), pair.second);
1119 }
1120 }
1121
1122 struct MarkedInstruction : Instruction {
1123 /* Additional marks are created in the process of parsing. */
1124 MarkedInstruction(Instruction instruction_) :
1125 Instruction(instruction_),
1126 instruction_class(get_instruction_class(instruction_)),
1127 opcode_in_modrm(false), opcode_in_imm(false), rex { } {
1128 if (condrep) {
1129 optional_prefixes.insert("condrep");
1130 }
1131 if (rep) {
1132 optional_prefixes.insert("rep");
1133 }
1134 for (auto opcode_it = opcodes.begin(); opcode_it != opcodes.end(); ++opcod e_it) {
1135 auto opcode = *opcode_it;
1136 if (opcode == "/") {
1137 opcode_in_imm = true;
1138 break;
1139 } else if (opcode.find('/') != opcode.npos) {
1140 opcode_in_modrm = true;
1141 break;
1142 }
1143 }
1144 /* If register is stored in opcode we need to expand opcode now. */
1145 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++o perand_it) {
1146 auto &operand = *operand_it;
1147 if (operand.source == 'r') {
1148 auto opcode = opcodes.rbegin();
1149 for (; opcode != opcodes.rend(); ++opcode) {
1150 if (opcode->find('/') == opcode->npos) {
1151 auto saved_opcode = *opcode;
1152 switch (*(opcode->rbegin())) {
1153 case '0':
1154 (*opcode) = "(";
1155 opcode->append(saved_opcode);
1156 for (auto c = '1'; c <= '7'; ++c) {
1157 opcode->push_back('|');
1158 (*(saved_opcode.rbegin())) = c;
1159 opcode->append(saved_opcode);
1160 }
1161 opcode->push_back(')');
1162 if (saved_opcode == "0x97") {
1163 opcode->erase(1, 5);
1164 }
1165 break;
1166 case '8':
1167 (*opcode) = "(";
1168 opcode->append(saved_opcode);
1169 static const char cc[] = {'9', 'a', 'b', 'c', 'd', 'e', 'f'};
1170 for (int c_it = 0; c_it < arraysize(cc); ++c_it) {
1171 auto c = cc[c_it];
1172 opcode->push_back('|');
1173 (*(saved_opcode.rbegin())) = c;
1174 opcode->append(saved_opcode);
1175 }
1176 opcode->push_back(')');
1177 break;
1178 default:
1179 fprintf(stderr, _("%s: error - can not use “r” operand in "
1180 "instruction “%s”"), short_program_name, name.c_str());
1181 exit(1);
1182 }
1183 if (operand.size != "7") rex.b = true;
1184 break;
1185 }
1186 }
1187 if (opcode == opcodes.rend()) {
1188 fprintf(stderr, _("%s: error - can not use “r” operand in "
1189 "instruction “%s”"), short_program_name, name.c_str());
1190 exit(1);
1191 }
1192 break;
1193 }
1194 }
1195 /* Some “opcodes” include prefixes, move them there. */
1196 static std::set<std::string> opcode_prefixes = {
1197 "0x66", "data16",
1198 "0xf0", "lock",
1199 "0xf2", "repnz",
1200 "0xf3", "repz",
1201 "rexw"
1202 };
1203 while (opcode_prefixes.find(*opcodes.begin()) != opcode_prefixes.end()) {
1204 if ((*opcodes.begin()) == "rexw") {
1205 if (!rex.w && instruction_class == InstructionClass::kDefault) {
1206 instruction_class = InstructionClass::kRexW;
1207 rex.w = true;
1208 } else if (!rex.w && instruction_class == InstructionClass::kSize8) {
1209 instruction_class = InstructionClass::kSize8RexW;
1210 rex.w = true;
1211 } else {
1212 fprintf(stderr, _("%s: error - can not enforce “%drexw” prefix in "
1213 "instruction “%s”"), short_program_name, instruction_cl ass, name.c_str());
1214 exit(1);
1215 }
1216 } else {
1217 required_prefixes.insert(*opcodes.begin());
1218 }
1219 opcodes.erase(opcodes.begin());
1220 }
1221 }
1222
1223 enum InstructionClass {
1224 kDefault,
1225 /* The same as kDefault, but to make “dil”/“sil”/“bpl”/“spl” accesible
1226 pure REX (hex 0x40) is allowed. */
1227 kSize8,
1228 /* One operand is kSize8, another is RexW. */
1229 kSize8RexW,
1230 kData16,
1231 kRexW,
1232 /* Combinations: must generate few different lines. */
1233 kDefaultRexW,
1234 kData16DefaultRexW,
1235 kSize8Data16DefaultRexW,
1236 kLSetUnset,
1237 kLSetUnsetDefaultRexW,
1238 /* Unknown: if all arguments are unknown the result is kDefault. */
1239 kUnknown
1240 } instruction_class;
1241 std::multiset<std::string> required_prefixes;
1242 std::multiset<std::string> optional_prefixes;
1243 struct {
1244 bool b : 1;
1245 bool x : 1;
1246 bool r : 1;
1247 bool w : 1;
1248 } rex;
1249 bool opcode_in_modrm : 1;
1250 bool opcode_in_imm : 1;
1251
1252 static InstructionClass get_instruction_class(
1253 const Instruction &instruction) {
1254 InstructionClass instruction_class = InstructionClass::kUnknown;
1255 for (auto operand_it = instruction.operands.begin(); operand_it != instruc tion.operands.end(); ++operand_it) {
1256 auto &operand = *operand_it;
1257 static const std::map<std::string, InstructionClass> classes_map {
1258 /* “size8” is special “prefix” not included in AMD manual: w bit in
1259 opcode switches between 8bit and 16/32/64 bit versions. M is just
1260 an address in memory: it means register-only encodings are invalid,
1261 but other operands decide everything else. */
1262 { "", InstructionClass::kSize8Data16DefaultRexW },
1263 { "2", InstructionClass::kUnknown },
1264 { "7", InstructionClass::kUnknown },
1265 { "d", InstructionClass::kUnknown },
1266 { "do", InstructionClass::kUnknown },
1267 { "dq", InstructionClass::kUnknown },
1268 { "fq", InstructionClass::kUnknown },
1269 { "o", InstructionClass::kUnknown },
1270 { "p", InstructionClass::kUnknown },
1271 { "pb", InstructionClass::kUnknown },
1272 { "pd", InstructionClass::kUnknown },
1273 { "pdw", InstructionClass::kUnknown },
1274 { "pdwx", InstructionClass::kLSetUnset },
1275 { "pdx", InstructionClass::kLSetUnset },
1276 { "ph", InstructionClass::kUnknown },
1277 { "pi", InstructionClass::kUnknown },
1278 { "pj", InstructionClass::kUnknown },
1279 { "pjx", InstructionClass::kLSetUnset },
1280 { "pk", InstructionClass::kUnknown },
1281 { "pq", InstructionClass::kUnknown },
1282 { "pqw", InstructionClass::kUnknown },
1283 { "pqwx", InstructionClass::kLSetUnset },
1284 { "ps", InstructionClass::kUnknown },
1285 { "psx", InstructionClass::kLSetUnset },
1286 { "pw", InstructionClass::kUnknown },
1287 { "q", InstructionClass::kUnknown },
1288 { "r", InstructionClass::kUnknown },
1289 { "s", InstructionClass::kUnknown },
1290 { "sb", InstructionClass::kUnknown },
1291 { "sd", InstructionClass::kUnknown },
1292 { "se", InstructionClass::kUnknown },
1293 { "si", InstructionClass::kUnknown },
1294 { "sq", InstructionClass::kUnknown },
1295 { "sr", InstructionClass::kUnknown },
1296 { "ss", InstructionClass::kUnknown },
1297 { "st", InstructionClass::kUnknown },
1298 { "sw", InstructionClass::kUnknown },
1299 { "sx", InstructionClass::kUnknown },
1300 { "v", InstructionClass::kData16DefaultRexW },
1301 { "w", InstructionClass::kUnknown },
1302 { "x", InstructionClass::kLSetUnset },
1303 { "y", InstructionClass::kDefaultRexW },
1304 { "z", InstructionClass::kData16DefaultRexW }
1305 };
1306 InstructionClass operand_class;
1307 auto it = classes_map.find(operand.size);
1308 if (it != classes_map.end()) {
1309 operand_class = it->second;
1310 /* If it's 8bit register specified using ModRM then we mark it as size8
1311 to make it possible to use REX_NONE for “dil”/“sil”/“bpl”/“spl”. */
1312 } else if (operand.size == "b") {
1313 if ((operand.source == 'E') ||
1314 (operand.source == 'G') ||
1315 (operand.source == 'M') ||
1316 (operand.source == 'R') ||
1317 (operand.source == 'r')) {
1318 operand_class = InstructionClass::kSize8;
1319 } else {
1320 operand_class = InstructionClass::kUnknown;
1321 }
1322 } else {
1323 fprintf(stderr, _("%s: unknown operand: “%c%s”\n"),
1324 short_program_name, operand.source, operand.size.c_str());
1325 exit(1);
1326 }
1327 if ((operand_class == InstructionClass::kUnknown) ||
1328 (instruction_class == operand_class)) {
1329 ; /* Do nothing: operand_class does not change anything. */
1330 } else if (instruction_class == InstructionClass::kUnknown) {
1331 instruction_class = operand_class;
1332 } else if (((instruction_class == InstructionClass::kDefaultRexW) &&
1333 (operand_class ==
1334 InstructionClass::kSize8Data16DefaultRexW)) ||
1335 ((instruction_class ==
1336 InstructionClass::kSize8Data16DefaultRexW) &&
1337 (operand_class == InstructionClass::kDefaultRexW))) {
1338 instruction_class = InstructionClass::kSize8Data16DefaultRexW;
1339 } else {
1340 fprintf(stderr, _("%s: error - incompatible modes %d & %d\n"),
1341 short_program_name, instruction_class, operand_class);
1342 exit(1);
1343 }
1344 }
1345 switch (instruction_class) {
1346 case InstructionClass::kUnknown:
1347 return InstructionClass::kDefault;
1348 default:
1349 return instruction_class;
1350 }
1351 }
1352
1353 void print_one_size_definition_data16(void) {
1354 auto saved_prefixes = required_prefixes;
1355 required_prefixes.insert("data16");
1356 print_one_size_definition();
1357 required_prefixes = saved_prefixes;
1358 }
1359
1360 void print_one_size_definition_rexw(void) {
1361 auto saved_rex = rex;
1362 rex.w = true;
1363 print_one_size_definition();
1364 rex = saved_rex;
1365 }
1366
1367 void print_definition(void) {
1368 switch (auto saved_class = instruction_class) {
1369 case InstructionClass::kDefault:
1370 case InstructionClass::kSize8:
1371 print_one_size_definition();
1372 break;
1373 case InstructionClass::kSize8RexW:
1374 case InstructionClass::kRexW:
1375 print_one_size_definition_rexw();
1376 break;
1377 case InstructionClass::kData16:
1378 print_one_size_definition_data16();
1379 break;
1380 case InstructionClass::kDefaultRexW:
1381 instruction_class = InstructionClass::kDefault;
1382 print_one_size_definition();
1383 instruction_class = InstructionClass::kRexW;
1384 print_one_size_definition_rexw();
1385 instruction_class = saved_class;
1386 break;
1387 case InstructionClass::kData16DefaultRexW:
1388 instruction_class = InstructionClass::kData16;
1389 print_one_size_definition_data16();
1390 instruction_class = InstructionClass::kDefault;
1391 print_one_size_definition();
1392 instruction_class = InstructionClass::kRexW;
1393 print_one_size_definition_rexw();
1394 instruction_class = saved_class;
1395 break;
1396 case InstructionClass::kSize8Data16DefaultRexW:
1397 instruction_class = InstructionClass::kSize8;
1398 print_one_size_definition();
1399 for (auto opcode = opcodes.rbegin(); opcode != opcodes.rend();
1400 ++opcode) {
1401 if (opcode->find('/') == opcode->npos) {
1402 /* “w” bit is last bit both in binary and textual form. */
1403 *(opcode->rbegin()) += 0x1;
1404 instruction_class = InstructionClass::kData16;
1405 print_one_size_definition_data16();
1406 instruction_class = InstructionClass::kDefault;
1407 print_one_size_definition();
1408 instruction_class = InstructionClass::kRexW;
1409 print_one_size_definition_rexw();
1410 instruction_class = saved_class;
1411 return;
1412 }
1413 }
1414 fprintf(stderr, _("%s: error - can not set “w” bit in "
1415 "instruction “%s”"), short_program_name, name.c_str());
1416 exit(1);
1417 case InstructionClass::kLSetUnset:
1418 case InstructionClass::kLSetUnsetDefaultRexW:
1419 for (auto opcode_it = opcodes.begin(); opcode_it != opcodes.end(); ++o pcode_it) {
1420 auto &opcode = *opcode_it;
1421 auto Lbit = opcode.find(".L.");
1422 if (Lbit != opcode.npos) {
1423 opcode[++Lbit] = '1';
1424 instruction_class = InstructionClass::kDefault;
1425 print_one_size_definition();
1426 if (saved_class == InstructionClass::kLSetUnsetDefaultRexW) {
1427 instruction_class = InstructionClass::kRexW;
1428 print_one_size_definition_rexw();
1429 }
1430 opcode[Lbit] = '0';
1431 auto saved_operands = operands;
1432 for (auto operand_it = operands.begin(); operand_it != operands.en d(); ++operand_it) {
1433 auto &operand = *operand_it;
1434 static const char cc[] = {'H', 'L', 'U', 'V', 'W'};
1435 for (int c_it = 0; c_it < arraysize(cc); ++c_it) {
1436 auto c = cc[c_it];
1437 if ((operand.source == c) &&
1438 (*(operand.size.rbegin()) == 'x') &&
1439 (((operand.size.length() > 1) &&
1440 (operand.size[0] == 'p')) ||
1441 (operand.size.length() == 1))) {
1442 operand.size.resize(operand.size.length() - 1);
1443 }
1444 }
1445 }
1446 instruction_class = InstructionClass::kDefault;
1447 print_one_size_definition();
1448 if (saved_class == InstructionClass::kLSetUnsetDefaultRexW) {
1449 instruction_class = InstructionClass::kRexW;
1450 print_one_size_definition_rexw();
1451 }
1452 operands = saved_operands;
1453 return;
1454 }
1455 }
1456 fprintf(stderr, _("%s: error - can not set “L” bit in"
1457 "instruction “%s”"), short_program_name, name.c_str());
1458 exit(1);
1459 break;
1460 case InstructionClass::kUnknown:
1461 fprintf(stderr, _("%s: error - incorrect operand mode: “%d”"),
1462 short_program_name, instruction_class);
1463 exit(1);
1464 }
1465 }
1466
1467 void print_one_size_definition(void) {
1468 /* 64bit commands are not supported in ia32 mode. */
1469 if (ia32_mode && rex.w) {
1470 return;
1471 }
1472 bool modrm_memory = false;
1473 bool modrm_register = false;
1474 char operand_source;
1475 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++o perand_it) {
1476 auto &operand = *operand_it;
1477 static std::map<char, std::pair<bool, bool> > operand_map {
1478 { 'E', std::make_pair(true, true ) },
1479 { 'M', std::make_pair(true, false) },
1480 { 'N', std::make_pair(false, true ) },
1481 { 'Q', std::make_pair(true, true ) },
1482 { 'R', std::make_pair(false, true ) },
1483 { 'U', std::make_pair(false, true ) },
1484 { 'W', std::make_pair(true, true ) }
1485 };
1486 auto it = operand_map.find(operand.source);
1487 if (it != operand_map.end()) {
1488 if ((modrm_memory || modrm_register) &&
1489 ((modrm_memory != it->second.first) ||
1490 (modrm_register != it->second.second))) {
1491 fprintf(stderr, _("%s: error - conflicting operand sources: “%c”"
1492 " and “%c”"), short_program_name, operand_source, operand.source);
1493 exit(1);
1494 }
1495 modrm_memory = it->second.first;
1496 modrm_register = it->second.second;
1497 operand_source = operand.source;
1498 }
1499 }
1500 if (modrm_memory || modrm_register) {
1501 if (modrm_memory) {
1502 auto saved_prefixes = optional_prefixes;
1503 /* optional_prefixes.insert("(segfs | seggs)"); */
1504 print_one_size_definition_modrm_memory();
1505 if (lock) {
1506 auto saved_prefixes = required_prefixes;
1507 required_prefixes.insert("lock");
1508 print_one_size_definition_modrm_memory();
1509 required_prefixes = saved_prefixes;
1510 }
1511 optional_prefixes = saved_prefixes;
1512 }
1513 if (modrm_register) {
1514 print_one_size_definition_modrm_register();
1515 }
1516 } else {
1517 print_one_size_definition_nomodrm();
1518 }
1519 }
1520
1521 void print_one_size_definition_nomodrm(void) {
1522 print_operator_delimeter();
1523 print_legacy_prefixes();
1524 print_rex_prefix();
1525 print_opcode_nomodrm();
1526 if (opcode_in_imm) {
1527 print_immediate_opcode();
1528 print_opcode_recognition();
1529 } else {
1530 print_opcode_recognition();
1531 print_immediate_arguments();
1532 }
1533 }
1534
1535 void print_one_size_definition_modrm_register(void) {
1536 print_operator_delimeter();
1537 if (mod_reg_is_used()) {
1538 rex.r = true;
1539 }
1540 if (mod_rm_is_used()) {
1541 rex.b = true;
1542 }
1543 print_legacy_prefixes();
1544 print_rex_prefix();
1545 print_opcode_nomodrm();
1546 if (!opcode_in_imm) {
1547 print_opcode_recognition();
1548 }
1549 fprintf(out_file, " modrm_registers");
1550 if (enabled(Actions::kParseOperands)) {
1551 for (auto operand_it = operands.begin(); operand_it != operands.end(); + +operand_it) {
1552 auto &operand = *operand_it;
1553 static const std::map<char, const char*> operand_type {
1554 { 'C', "reg" },
1555 { 'D', "reg" },
1556 { 'E', "rm" },
1557 { 'G', "reg" },
1558 { 'M', "rm" },
1559 { 'N', "rm" },
1560 { 'P', "reg" },
1561 { 'Q', "rm" },
1562 { 'R', "rm" },
1563 { 'S', "reg" },
1564 { 'U', "rm" },
1565 { 'V', "reg" },
1566 { 'W', "rm" }
1567 };
1568 auto it = operand_type.find(operand.source);
1569 if (it != operand_type.end()) {
1570 fprintf(out_file, " @operand%zd_from_modrm_%s",
1571 &operand - &*operands.begin(), it->second);
1572 }
1573 }
1574 }
1575 if (opcode_in_modrm) {
1576 fprintf(out_file, ")");
1577 }
1578 if (opcode_in_imm) {
1579 print_immediate_opcode();
1580 print_opcode_recognition();
1581 } else {
1582 print_immediate_arguments();
1583 }
1584 }
1585
1586 void print_one_size_definition_modrm_memory(void) {
1587 typedef std::tuple<const char *, bool, bool> T;
1588 static const T modes[] = {
1589 T { " operand_disp", false, true },
1590 T { " operand_rip", false, false },
1591 T { " single_register_memory", false, true },
1592 T { " operand_sib_pure_index", true, false },
1593 T { " operand_sib_base_index", true, true }
1594 };
1595 for (int mode_it = 0; mode_it < arraysize(modes); ++mode_it) {
1596 auto mode = modes[mode_it];
1597 print_operator_delimeter();
1598 if (mod_reg_is_used()) {
1599 rex.r = true;
1600 }
1601 if (mod_rm_is_used()) {
1602 rex.x = std::get<1>(mode);
1603 rex.b = std::get<2>(mode);
1604 }
1605 print_legacy_prefixes();
1606 print_rex_prefix();
1607 print_opcode_nomodrm();
1608 if (!opcode_in_imm) {
1609 print_opcode_recognition();
1610 }
1611 if (opcode_in_modrm) {
1612 fprintf(out_file, " any");
1613 } else {
1614 fprintf(out_file, " (any");
1615 }
1616 if (enabled(Actions::kParseOperands)) {
1617 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++operand_it) {
1618 auto &operand = *operand_it;
1619 static const std::map<char, const char*> operand_type {
1620 { 'C', "from_modrm_reg" },
1621 { 'D', "from_modrm_reg" },
1622 { 'E', "rm" },
1623 { 'G', "from_modrm_reg" },
1624 { 'M', "rm" },
1625 { 'N', "rm" },
1626 { 'P', "from_modrm_reg" },
1627 { 'Q', "rm" },
1628 { 'R', "rm" },
1629 { 'S', "from_modrm_reg" },
1630 { 'U', "rm" },
1631 { 'V', "from_modrm_reg" },
1632 { 'W', "rm" }
1633 };
1634 auto it = operand_type.find(operand.source);
1635 if (it != operand_type.end()) {
1636 fprintf(out_file, " @operand%zd_%s",
1637 &operand - &*operands.begin(), it->second);
1638 }
1639 }
1640 }
1641 fprintf(out_file, " . any* &%s", std::get<0>(mode));
1642 if (enabled(Actions::kCheckAccess) && !no_memory_access) {
1643 fprintf(out_file, " @check_access");
1644 }
1645 fprintf(out_file, ")");
1646 if (opcode_in_imm) {
1647 print_immediate_opcode();
1648 print_opcode_recognition();
1649 } else {
1650 print_immediate_arguments();
1651 }
1652 }
1653 }
1654
1655 #if 0
1656 /* We need GCC 4.7 to use the following. */
1657 static auto first_delimeter = true;
1658 #else
1659 static bool first_delimeter;
1660 #endif
1661 void print_operator_delimeter(void) {
1662 if (first_delimeter) {
1663 fprintf(out_file, "\n (");
1664 } else {
1665 fprintf(out_file, ") |\n (");
1666 }
1667 first_delimeter = false;
1668 }
1669
1670 bool mod_reg_is_used() {
1671 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++o perand_it) {
1672 auto &operand = *operand_it;
1673 if (operand.source == 'C' &&
1674 required_prefixes.find("0xf0") == required_prefixes.end()) {
1675 return true;
1676 }
1677 static const char cc[] = { 'G', 'P', 'V' };
1678 for (int c_it = 0; c_it < arraysize(cc); ++c_it) {
1679 auto c = cc[c_it];
1680 if (operand.source == c) {
1681 return true;
1682 }
1683 }
1684 }
1685 return false;
1686 }
1687
1688 bool mod_rm_is_used() {
1689 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++o perand_it) {
1690 auto &operand = *operand_it;
1691 static const char cc[] = { 'E', 'M', 'N', 'Q', 'R', 'U', 'W' };
1692 for (int c_it = 0; c_it < arraysize(cc); ++c_it) {
1693 auto c = cc[c_it];
1694 if (operand.source == c) {
1695 return true;
1696 }
1697 }
1698 }
1699 return false;
1700 }
1701
1702 void print_legacy_prefixes(void) {
1703 if ((required_prefixes.size() == 1) &&
1704 (optional_prefixes.size() == 0)) {
1705 fprintf(out_file, "%s ", required_prefixes.begin()->c_str());
1706 } else if ((required_prefixes.size() == 0) &&
1707 (optional_prefixes.size() == 1)) {
1708 fprintf(out_file, "%s? ", optional_prefixes.begin()->c_str());
1709 } else if ((optional_prefixes.size() > 0) ||
1710 (required_prefixes.size() > 0)) {
1711 auto delimeter = "(";
1712 auto opt_start = required_prefixes.size() ? 0 : 1;
1713 auto opt_end = 1 << optional_prefixes.size();
1714 for (auto opt = opt_start; opt < opt_end; ++opt) {
1715 auto prefixes = required_prefixes;
1716 auto it = optional_prefixes.begin();
1717 for (auto id = 1; id < opt_end; id <<= 1, ++it) {
1718 if (opt & id) {
1719 prefixes.insert(*it);
1720 }
1721 }
1722 if (prefixes.size() == 1) {
1723 fprintf(out_file, "%s%s", delimeter, prefixes.begin()->c_str());
1724 delimeter = " | ";
1725 } else {
1726 std::vector<std::string> permutations(prefixes.begin(),
1727 prefixes.end());
1728 do {
1729 fprintf(out_file, "%s", delimeter);
1730 delimeter = " | ";
1731 auto delimeter = '(';
1732 for (auto prefix_it = permutations.begin(); prefix_it != permutati ons.end(); ++prefix_it) {
1733 auto &prefix = *prefix_it;
1734 fprintf(out_file, "%c%s", delimeter, prefix.c_str());
1735 delimeter = ' ';
1736 }
1737 fprintf(out_file, ")");
1738 } while (next_permutation(permutations.begin(),
1739 permutations.end()));
1740 }
1741 }
1742 if (opt_start) {
1743 fprintf(out_file, ")? ");
1744 } else {
1745 fprintf(out_file, ") ");
1746 }
1747 }
1748 }
1749
1750 void print_rex_prefix(void) {
1751 /* Prefix REX is not used in ia32 mode. */
1752 if (ia32_mode) {
1753 return;
1754 }
1755 /* VEX/XOP instructions integrate REX bits and opcode bits. They will
1756 be printed in print_opcode_nomodrm. */
1757 if ((opcodes.size() >= 3) &&
1758 ((opcodes[0] == "0xc4") ||
1759 ((opcodes[0] == "0x8f") && (opcodes[1] != "/0")))) {
1760 return;
1761 }
1762 if (rex.w || rex.r || rex.x || rex.b) {
1763 if (!rex.r && !rex.x && ! rex.b) {
1764 fprintf(out_file, "REXW_NONE ");
1765 } else {
1766 if (rex.w) {
1767 fprintf(out_file, "REXW_");
1768 if (rex.r) fprintf(out_file, "R");
1769 if (rex.x) fprintf(out_file, "X");
1770 if (rex.b) fprintf(out_file, "B");
1771 fprintf(out_file, " ");
1772 } else if (instruction_class == InstructionClass::kSize8 ||
1773 instruction_class == InstructionClass::kSize8RexW) {
1774 fprintf(out_file, "REX_");
1775 if (rex.r) fprintf(out_file, "R");
1776 if (rex.x) fprintf(out_file, "X");
1777 if (rex.b) fprintf(out_file, "B");
1778 fprintf(out_file, "? ");
1779 } else {
1780 fprintf(out_file, "rex_");
1781 if (rex.r) fprintf(out_file, "r");
1782 if (rex.x) fprintf(out_file, "x");
1783 if (rex.b) fprintf(out_file, "b");
1784 fprintf(out_file, "? ");
1785 }
1786 }
1787 }
1788 }
1789
1790 void print_third_byte(const std::string& third_byte) const {
1791 auto byte = 0;
1792 for (auto i = 7, p = 1; i>=0; --i, p <<= 1) {
1793 if (third_byte[i] == '1' || third_byte[i] == 'X' ||
1794 ((third_byte[i] == 'W') && rex.w)) {
1795 byte |= p;
1796 }
1797 }
1798 if (third_byte.find('X') == third_byte.npos) {
1799 fprintf(out_file, "0x%02x", byte);
1800 } else {
1801 std::set<decltype(byte)> bytes { byte };
1802 for (auto i = 7, p = 1; i>=0; --i, p <<= 1) {
1803 if (third_byte[i] == 'X') {
1804 for (auto byte_it = bytes.begin(); byte_it != bytes.end(); ++byte_it ) {
1805 auto &byte = *byte_it;
1806 bytes.insert(byte & ~p);
1807 }
1808 }
1809 }
1810 auto delimeter = "(";
1811 for (auto byte_it = bytes.begin(); byte_it != bytes.end(); ++byte_it) {
1812 auto &byte = *byte_it;
1813 fprintf(out_file, "%s0x%02x", delimeter, byte);
1814 delimeter = " | ";
1815 }
1816 fprintf(out_file, ")");
1817 }
1818 }
1819
1820 void print_opcode_nomodrm(void) {
1821 if ((opcodes.size() == 1) ||
1822 ((opcodes.size() == 2) &&
1823 (opcodes[1].find('/') != opcodes[1].npos))) {
1824 if (opcodes[0].find('/') == opcodes[0].npos) {
1825 if ((instruction_class == InstructionClass::kData16) &&
1826 (opcodes[0] == "(0x91|0x92|0x93|0x94|0x95|0x96|0x97)")) {
1827 fprintf(out_file, "(0x90|0x91|0x92|0x93|0x94|0x95|0x96|0x97)");
1828 } else {
1829 fprintf(out_file, "%s", opcodes[0].c_str());
1830 }
1831 }
1832 } else if ((opcodes.size() >= 3) &&
1833 ((opcodes[0] == "0xc4") ||
1834 ((opcodes[0] == "0x8f") && (opcodes[1] != "/0"))) &&
1835 (opcodes[1].substr(0, 4) == "RXB.")) {
1836 auto c5_ok = (opcodes[0] == "0xc4") &&
1837 ((opcodes[1] == "RXB.01") ||
1838 (opcodes[1] == "RXB.00001")) &&
1839 ((*opcodes[2].begin() == '0') ||
1840 (*opcodes[2].begin() == 'x') ||
1841 (*opcodes[2].begin() == 'X'));
1842 if (c5_ok) fprintf(out_file, "((");
1843 fprintf(out_file, "(%s (VEX_", opcodes[0].c_str());
1844 if (ia32_mode || (!rex.r && !rex.x & !rex.b)) {
1845 fprintf(out_file, "NONE");
1846 } else {
1847 if (rex.r) fprintf(out_file, "R");
1848 if (rex.x) fprintf(out_file, "X");
1849 if (rex.b) fprintf(out_file, "B");
1850 }
1851 fprintf(out_file, " & VEX_map%s) ", opcodes[1].c_str() + 4);
1852 auto third_byte = opcodes[2];
1853 #if 0
1854 /* We need GCC 4.8 for the following. */
1855 static const std::regex third_byte_check(
1856 R"([01xX]\.[01xX][01xX][01xX][01xX]\.[01xX]\.[01][01])");
1857 if ((third_byte.length() != 11) ||
1858 !regex_match(third_byte.begin(), third_byte.end(),
1859 third_byte_check)) {
1860 #else
1861 static const char* symbolic_names[] = { "cntl", "dest", "src1", "src" };
1862 for (int symbolic_it = 0; symbolic_it < arraysize(symbolic_names); ++sym bolic_it) {
1863 auto symbolic = symbolic_names[symbolic_it];
1864 for (auto it = third_byte.begin(); it != third_byte.end(); ++it) {
1865 if ((third_byte.end() - it) >= strlen(symbolic) &&
1866 !strncmp(&*it, symbolic, strlen(symbolic))) {
1867 third_byte.replace(it, it + strlen(symbolic), "XXXX");
1868 break;
1869 }
1870 }
1871 }
1872 static const std::set<char> third_byte_check[] {
1873 { '0', '1', 'x', 'X', 'W' },
1874 { '.' },
1875 { '0', '1', 'x', 'X' },
1876 { '0', '1', 'x', 'X' },
1877 { '0', '1', 'x', 'X' },
1878 { '0', '1', 'x', 'X' },
1879 { '.' },
1880 { '0', '1', 'x', 'X' },
1881 { '.' },
1882 { '0', '1' },
1883 { '0', '1' }
1884 };
1885 auto third_byte_ok = (arraysize(third_byte_check) ==
1886 third_byte.length());
1887 if (third_byte_ok) {
1888 for (int set_it = 0; set_it < arraysize(third_byte_check); ++set_it) {
1889 auto &set = third_byte_check[set_it];
1890 if (set.find(third_byte[&set - third_byte_check]) == set.end()) {
1891 third_byte_ok = false;
1892 break;
1893 }
1894 }
1895 }
1896 if (third_byte_ok) {
1897 #endif
1898 if (ia32_mode && third_byte[2] == 'X') {
1899 third_byte[2] = '1';
1900 }
1901 third_byte.erase(1, 1);
1902 third_byte.erase(5, 1);
1903 third_byte.erase(6, 1);
1904 print_third_byte(third_byte);
1905 if (enabled(Actions::kVexPrefix)) {
1906 fprintf(out_file, " @vex_prefix3");
1907 }
1908 if (c5_ok) {
1909 fprintf(out_file, ") | (0xc5 ");
1910 if (!ia32_mode && rex.r) {
1911 third_byte[0] = 'X';
1912 } else {
1913 third_byte[0] = '1';
1914 }
1915 print_third_byte(third_byte);
1916 if (enabled(Actions::kVexPrefix)) {
1917 fprintf(out_file, " @vex_prefix_short");
1918 }
1919 fprintf(out_file, "))");
1920 }
1921 for (auto opcode = ++++++opcodes.begin(); opcode != opcodes.end();
1922 ++opcode) {
1923
1924 if (opcode->find('/') == opcode->npos) {
1925 fprintf(out_file, " %s", opcode->c_str());
1926 } else {
1927 break;
1928 }
1929 }
1930 fprintf(out_file, ")");
1931 } else {
1932 fprintf(stderr, _("%s: error - third byte of VEX/XOP command "
1933 "in unparseable (%s) in instruction “%s”"),
1934 short_program_name, third_byte.c_str(), name.c_str());
1935 exit(1);
1936 }
1937 } else {
1938 auto delimeter = '(';
1939 for (auto opcode_it = opcodes.begin(); opcode_it != opcodes.end(); ++opc ode_it) {
1940 auto &opcode = *opcode_it;
1941 if (opcode.find('/') == opcode.npos) {
1942 fprintf(out_file, "%c%s", delimeter, opcode.c_str());
1943 delimeter = ' ';
1944 } else {
1945 break;
1946 }
1947 }
1948 fprintf(out_file, ")");
1949 }
1950 if (enabled(Actions::kOpcode)) {
1951 fprintf(out_file, " >begin_opcode");
1952 }
1953 if (enabled(Actions::kParseOperands)) {
1954 for (auto operand_it = operands.begin(); operand_it != operands.end(); + +operand_it) {
1955 auto &operand = *operand_it;
1956 if (operand.source == 'r') {
1957 fprintf(out_file, " @operand%zd_from_opcode",
1958 &operand - &*operands.begin());
1959 }
1960 }
1961 }
1962 }
1963
1964 void print_opcode_recognition(void) {
1965 if (opcode_in_modrm) {
1966 fprintf(out_file, " (");
1967 for (auto opcode = opcodes.rbegin(); opcode != opcodes.rend();
1968 ++opcode) {
1969 if ((*opcode) != "/" && opcode->find('/') != opcode->npos) {
1970 fprintf(out_file, "opcode_%s", opcode->c_str() + 1);
1971 }
1972 }
1973 }
1974 if (enabled(Actions::kOpcode)) {
1975 fprintf(out_file, " @end_opcode");
1976 }
1977 for (auto prefix_it = required_prefixes.begin(); prefix_it != required_pre fixes.end(); ++prefix_it) {
1978 auto &prefix = *prefix_it;
1979 if (prefix == "0x66") {
1980 fprintf(out_file, " @not_data16_prefix");
1981 break;
1982 }
1983 }
1984 for (auto prefix_it = required_prefixes.begin(); prefix_it != required_pre fixes.end(); ++prefix_it) {
1985 auto &prefix = *prefix_it;
1986 if (prefix == "0xf2") {
1987 fprintf(out_file, " @not_repnz_prefix");
1988 break;
1989 }
1990 }
1991 for (auto prefix_it = required_prefixes.begin(); prefix_it != required_pre fixes.end(); ++prefix_it) {
1992 auto &prefix = *prefix_it;
1993 if (prefix == "0xf3") {
1994 fprintf(out_file, " @not_repz_prefix");
1995 break;
1996 }
1997 }
1998 if (enabled(Actions::kInstructionName)) {
1999 fprintf(out_file, " @instruction_%s", c_identifier(name).c_str());
2000 }
2001 if (enabled(Actions::kParseOperands)) {
2002 fprintf(out_file, " @operands_count_is_%zd", operands.size());
2003 for (auto operand_it = operands.begin(); operand_it != operands.end(); + +operand_it) {
2004 auto &operand = *operand_it;
2005 typedef std::tuple<InstructionClass, char, std::string> T;
2006 static const std::map<T, const char*> operand_sizes {
2007 { T { InstructionClass::kDefault, ' ', "" }, "32bit" },
2008 { T { InstructionClass::kSize8, ' ', "" }, "8bit" },
2009 { T { InstructionClass::kData16, ' ', "" }, "16bit" },
2010 { T { InstructionClass::kRexW, ' ', "" }, "64bit" },
2011 { T { InstructionClass::kUnknown, 'H', "" }, "128bit" },
2012 { T { InstructionClass::kRexW, 'I', "" }, "32bit" },
2013 { T { InstructionClass::kUnknown, 'L', "" }, "128bit" },
2014 { T { InstructionClass::kUnknown, 'V', "" }, "128bit" },
2015 { T { InstructionClass::kUnknown, 'W', "" }, "128bit" },
2016 { T { InstructionClass::kUnknown, ' ', "2" }, "2bit" },
2017 { T { InstructionClass::kUnknown, ' ', "7" }, "x87" },
2018 { T { InstructionClass::kUnknown, ' ', "b" }, "8bit" },
2019 { T { InstructionClass::kUnknown, ' ', "d" }, "32bit" },
2020 { T { InstructionClass::kUnknown, ' ', "do" }, "256bit" },
2021 { T { InstructionClass::kUnknown, ' ', "dq" }, "128bit" },
2022 { T { InstructionClass::kUnknown, ' ', "fq" }, "256bit" },
2023 { T { InstructionClass::kUnknown, ' ', "o" }, "128bit" },
2024 { T { InstructionClass::kUnknown, ' ', "p" }, "farptr" },
2025 { T { InstructionClass::kUnknown, ' ', "pb" }, "xmm" },
2026 { T { InstructionClass::kUnknown, ' ', "pd" }, "xmm" },
2027 { T { InstructionClass::kUnknown, ' ', "pdw" }, "xmm" },
2028 { T { InstructionClass::kUnknown, ' ', "pdwx" }, "ymm" },
2029 { T { InstructionClass::kUnknown, ' ', "pdx" }, "ymm" },
2030 { T { InstructionClass::kUnknown, ' ', "ph" }, "xmm" },
2031 { T { InstructionClass::kUnknown, ' ', "pi" }, "xmm" },
2032 { T { InstructionClass::kUnknown, ' ', "pj" }, "xmm" },
2033 { T { InstructionClass::kUnknown, ' ', "pjx" }, "ymm" },
2034 { T { InstructionClass::kUnknown, ' ', "pk" }, "xmm" },
2035 { T { InstructionClass::kUnknown, ' ', "pq" }, "xmm" },
2036 { T { InstructionClass::kUnknown, ' ', "pqw" }, "xmm" },
2037 { T { InstructionClass::kUnknown, ' ', "pqwx" }, "ymm" },
2038 { T { InstructionClass::kUnknown, ' ', "ps" }, "xmm" },
2039 { T { InstructionClass::kUnknown, ' ', "psx" }, "ymm" },
2040 { T { InstructionClass::kUnknown, ' ', "pw" }, "xmm" },
2041 { T { InstructionClass::kUnknown, ' ', "q" }, "64bit" },
2042 { T { InstructionClass::kUnknown, 'N', "q" }, "mmx" },
2043 { T { InstructionClass::kUnknown, 'P', "q" }, "mmx" },
2044 { T { InstructionClass::kUnknown, 'Q', "q" }, "mmx" },
2045 { T { InstructionClass::kUnknown, 'U', "q" }, "xmm" },
2046 { T { InstructionClass::kUnknown, 'V', "q" }, "xmm" },
2047 { T { InstructionClass::kUnknown, 'W', "q" }, "xmm" },
2048 { T { InstructionClass::kUnknown, ' ', "r" }, "regsize" },
2049 { T { InstructionClass::kUnknown, 'C', "r" }, "creg" },
2050 { T { InstructionClass::kUnknown, 'D', "r" }, "dreg" },
2051 { T { InstructionClass::kUnknown, ' ', "s" }, "selector" },
2052 { T { InstructionClass::kUnknown, ' ', "sb" }, "x87_bcd" },
2053 { T { InstructionClass::kUnknown, ' ', "sd" }, "float64bit" },
2054 { T { InstructionClass::kUnknown, ' ', "se" }, "x87_env" },
2055 { T { InstructionClass::kUnknown, ' ', "si" }, "x87_32bit" },
2056 { T { InstructionClass::kUnknown, ' ', "sq" }, "x87_64bit" },
2057 { T { InstructionClass::kUnknown, ' ', "sr" }, "x87_state" },
2058 { T { InstructionClass::kUnknown, ' ', "ss" }, "float32bit" },
2059 { T { InstructionClass::kUnknown, ' ', "st" }, "float80bit" },
2060 { T { InstructionClass::kUnknown, ' ', "sw" }, "x87_16bit" },
2061 { T { InstructionClass::kUnknown, ' ', "sx" },
2062 "x87_mmx_xmm_state" },
2063 { T { InstructionClass::kData16, ' ', "v" }, "16bit" },
2064 { T { InstructionClass::kDefault, ' ', "v" }, "32bit" },
2065 { T { InstructionClass::kRexW, ' ', "v" }, "64bit" },
2066 { T { InstructionClass::kUnknown, ' ', "w" }, "16bit" },
2067 { T { InstructionClass::kUnknown, 'S', "w" }, "segreg" },
2068 { T { InstructionClass::kUnknown, 'H', "x" }, "256bit" },
2069 { T { InstructionClass::kUnknown, 'L', "x" }, "256bit" },
2070 { T { InstructionClass::kUnknown, 'V', "x" }, "256bit" },
2071 { T { InstructionClass::kUnknown, 'W', "x" }, "256bit" },
2072 { T { InstructionClass::kDefault, ' ', "y" }, "32bit" },
2073 { T { InstructionClass::kSize8, ' ', "y" }, "32bit" },
2074 { T { InstructionClass::kData16, ' ', "y" }, "32bit" },
2075 { T { InstructionClass::kDefault, ' ', "y" }, "32bit" },
2076 { T { InstructionClass::kRexW, ' ', "y" }, "64bit" },
2077 { T { InstructionClass::kData16, ' ', "z" }, "16bit" },
2078 { T { InstructionClass::kDefault, ' ', "z" }, "32bit" },
2079 { T { InstructionClass::kRexW, ' ', "z" }, "32bit" }
2080 };
2081 auto it = operand_sizes.find(T {instruction_class,
2082 operand.source, operand.size});
2083 if (it == operand_sizes.end()) {
2084 it = operand_sizes.find(T {InstructionClass::kUnknown,
2085 operand.source, operand.size});
2086 }
2087 if (it == operand_sizes.end()) {
2088 it = operand_sizes.find(T {instruction_class,
2089 ' ', operand.size});
2090 }
2091 if (it == operand_sizes.end()) {
2092 it = operand_sizes.find(T {instruction_class,
2093 operand.source, ""});
2094 }
2095 if (it == operand_sizes.end()) {
2096 it = operand_sizes.find(T {InstructionClass::kUnknown,
2097 ' ', operand.size});
2098 }
2099 if (it == operand_sizes.end()) {
2100 fprintf(stderr, _("%s: error - can not determine operand size: %c%s"
2101 ), short_program_name, operand.source, operand.size.c_str());
2102 exit(1);
2103 } else {
2104 fprintf(out_file, " @operand%zd_%s", &operand - &*operands.begin(),
2105 it->second);
2106 }
2107 static std::map<char, const char*> operand_type {
2108 { '1', "one" },
2109 { 'a', "rax" },
2110 { 'b', "ds_rbx" },
2111 { 'c', "rcx" },
2112 { 'd', "rdx" },
2113 { 'i', "second_immediate" },
2114 { 'o', "port_dx" },
2115 { 't', "st" },
2116 { 'B', "from_vex" },
2117 { 'H', "from_vex" },
2118 { 'I', "immediate" },
2119 { 'O', "absolute_disp" },
2120 { 'X', "ds_rsi" },
2121 { 'Y', "es_rdi" }
2122 };
2123 auto it2 = operand_type.find(operand.source);
2124 if (it2 != operand_type.end()) {
2125 fprintf(out_file, " @operand%zd_%s", &operand - &*operands.begin(),
2126 it2->second);
2127 }
2128 }
2129 }
2130 if (enabled(Actions::kParseOperandsStates)) {
2131 for (auto operand_it = operands.begin(); operand_it != operands.end(); + +operand_it) {
2132 auto &operand = *operand_it;
2133 if (operand.read) {
2134 if (operand.write) {
2135 fprintf(out_file, " @operand%zd_readwrite",
2136 &operand - &*operands.begin());
2137 } else {
2138 fprintf(out_file, " @operand%zd_read",
2139 &operand - &*operands.begin());
2140 }
2141 } else {
2142 if (operand.write) {
2143 fprintf(out_file, " @operand%zd_write",
2144 &operand - &*operands.begin());
2145 } else {
2146 fprintf(out_file, " @operand%zd_unused",
2147 &operand - &*operands.begin());
2148 }
2149 }
2150 }
2151 }
2152 if (opcode_in_modrm) {
2153 fprintf(out_file, " any* &");
2154 }
2155 }
2156
2157 void print_immediate_arguments(void) {
2158 for (auto operand = operands.rbegin(); operand != operands.rend();
2159 ++operand) {
2160 static const std::map<std::pair<InstructionClass, std::string>,
2161 const char*> immediate_sizes {
2162 { { InstructionClass::kDefault, "" }, "imm32" },
2163 { { InstructionClass::kSize8, "" }, "imm8" },
2164 { { InstructionClass::kData16, "" }, "imm16" },
2165 { { InstructionClass::kRexW, "" }, "imm32" },
2166 { { InstructionClass::kDefault, "2" }, "imm2" },
2167 { { InstructionClass::kDefault, "b" }, "imm8" },
2168 { { InstructionClass::kSize8, "b" }, "imm8" },
2169 { { InstructionClass::kData16, "b" }, "imm8" },
2170 { { InstructionClass::kRexW, "b" }, "imm8" },
2171 { { InstructionClass::kDefault, "d" }, "imm32" },
2172 { { InstructionClass::kRexW, "d" }, "imm32" },
2173 { { InstructionClass::kDefault, "v" }, "imm32" },
2174 { { InstructionClass::kData16, "v" }, "imm16" },
2175 { { InstructionClass::kRexW, "v" }, "imm64" },
2176 { { InstructionClass::kDefault, "w" }, "imm16" },
2177 { { InstructionClass::kDefault, "z" }, "imm32" },
2178 { { InstructionClass::kData16, "z" }, "imm16" },
2179 { { InstructionClass::kRexW, "z" }, "imm32" }
2180 };
2181 if (operand->source == 'i') {
2182 auto it = immediate_sizes.find({instruction_class,
2183 operand->size});
2184 if (it == immediate_sizes.end()) {
2185 fprintf(stderr, _("%s: error - can not determine immediate size: %c"
2186 "%s"), short_program_name, operand->source, operand->size.c_str());
2187 exit(1);
2188 }
2189 fprintf(out_file, " %sn2", it->second);
2190 }
2191 if (operand->source == 'I') {
2192 auto it = immediate_sizes.find({instruction_class,
2193 operand->size});
2194 if (it == immediate_sizes.end()) {
2195 fprintf(stderr, _("%s: error - can not determine immediate size: %c"
2196 "%s"), short_program_name, operand->source, operand->size.c_str());
2197 exit(1);
2198 }
2199 fprintf(out_file, " %s", it->second);
2200 }
2201 static const std::map<std::pair<InstructionClass, std::string>,
2202 const char *> jump_sizes {
2203 { { InstructionClass::kDefault, "b" }, "rel8" },
2204 { { InstructionClass::kDefault, "d" }, "rel32" },
2205 { { InstructionClass::kDefault, "w" }, "rel16" },
2206 { { InstructionClass::kDefault, "z" }, "rel32" },
2207 { { InstructionClass::kData16, "z" }, "rel16" },
2208 { { InstructionClass::kRexW, "z" }, "rel32" },
2209 };
2210 if (operand->source == 'J') {
2211 auto it = jump_sizes.find({instruction_class, operand->size});
2212 if (it == jump_sizes.end()) {
2213 fprintf(stderr, _("%s: error - can not determine jump size: %c%s"),
2214 short_program_name, operand->source, operand->size.c_str());
2215 exit(1);
2216 }
2217 fprintf(out_file, " %s", it->second);
2218 }
2219 if (operand->source == 'L') {
2220 if (operands.size() == 4) {
2221 if (ia32_mode) {
2222 fprintf(out_file, " %s", chartest((c & 0x8f) == 0x00));
2223 } else {
2224 fprintf(out_file, " %s", chartest((c & 0x0f) == 0x00));
2225 }
2226 }
2227 if (enabled(Actions::kParseOperands)) {
2228 fprintf(out_file, " @operand%zd_from_is4",
2229 operands.rend() - operand - 1);
2230 }
2231 }
2232 if (operand->source == 'O') {
2233 if (ia32_mode) {
2234 fprintf(out_file, " disp32");
2235 } else {
2236 fprintf(out_file, " disp64");
2237 }
2238 }
2239 }
2240 for (auto prefix_it = required_prefixes.begin(); prefix_it != required_pre fixes.end(); ++prefix_it) {
2241 auto &prefix = *prefix_it;
2242 if (prefix == "0xf0") {
2243 for (auto operand_it = operands.begin(); operand_it != operands.end(); ++operand_it) {
2244 auto &operand = *operand_it;
2245 if (operand.source == 'C') {
2246 fprintf(out_file, " @not_lock_prefix%zd",
2247 &operand - &*operands.begin());
2248 break;
2249 }
2250 }
2251 break;
2252 }
2253 }
2254 }
2255
2256 void print_immediate_opcode(void) {
2257 auto print_opcode = false;
2258 for (auto opcode_it = opcodes.begin(); opcode_it != opcodes.end(); ++opcod e_it) {
2259 auto &opcode = *opcode_it;
2260 if (opcode == "/") {
2261 print_opcode = true;
2262 } else if (print_opcode) {
2263 fprintf(out_file, " %s", opcode.c_str());
2264 }
2265 }
2266 }
2267 };
2268
2269 void print_one_instruction_definition(void) {
2270 for (auto instruction_it = instructions.begin(); instruction_it != instructi ons.end(); ++instruction_it) {
2271 auto &instruction = *instruction_it;
2272 MarkedInstruction(instruction).print_definition();
2273 }
2274 }
2275 #if 1
2276 /* We need GCC 4.7 to remove the following */
2277 bool MarkedInstruction::first_delimeter = true;
2278 #endif
2279 }
2280
2281 struct compare_action {
2282 const char* action;
2283
2284 compare_action(const char* y) : action(y) {
2285 }
2286
2287 bool operator()(const char* x) const {
2288 return !strcmp(x, action);
2289 }
2290 };
2291
2292 int main(int argc, char *argv[]) {
2293 setlocale(LC_ALL, "");
2294 bindtextdomain("ncval", ".");
2295 textdomain("ncval");
2296
2297 /* basename(3) may change the passed argument thus we are using copy
2298 of argv[0]. This creates tiny memory leak but since we only do that
2299 once per program invocation it's contained. */
2300 short_program_name = basename(strdup(argv[0]));
2301
2302 for (;;) {
2303 int option_index;
2304
2305 int option = getopt_long(argc, argv, "d:hm:o:v",
2306 kProgramOptions, &option_index);
2307
2308 if (option == -1) {
2309 break;
2310 }
2311
2312 switch (option) {
2313 #if 0
2314 case 0:
2315 printf("option %s", kProgramOptions[option_index].name);
2316 if (optarg)
2317 printf(" with arg %s", optarg);
2318 printf("\n");
2319 break;
2320 #endif
2321 case 'd': {
2322 for (auto action_to_disable = strtok(optarg, ",");
2323 action_to_disable;
2324 action_to_disable = strtok(NULL, ",")) {
2325 compare_action compare_with_action_to_disable(action_to_disable);
2326 auto action_number = std::find_if(
2327 kDisablableActionsList,
2328 kDisablableActionsList + arraysize(kDisablableActionsList),
2329 compare_with_action_to_disable);
2330 if (action_number !=
2331 kDisablableActionsList + arraysize(kDisablableActionsList)) {
2332 disabled_actions[action_number - kDisablableActionsList] = true;
2333 } else {
2334 fprintf(stderr, _("%s: action “%s” is unknown\n"),
2335 short_program_name, action_to_disable);
2336 return 1;
2337 }
2338 }
2339 break;
2340 }
2341 case 'm': {
2342 if (!strcmp(optarg, "ia32")) {
2343 ia32_mode = true;
2344 } else if (!strcmp(optarg, "amd64")) {
2345 ia32_mode = false;
2346 } else {
2347 fprintf(stderr, _("%s: mode “%s” is unknown\n"),
2348 short_program_name, optarg);
2349 return 1;
2350 }
2351 break;
2352 }
2353 case 'o':
2354 out_file_name = optarg;
2355 break;
2356 case 'h':
2357 printf(gettext(kProgramHelp), short_program_name);
2358 break;
2359 case 'v':
2360 printf(gettext(kVersionHelp), short_program_name, kVersion);
2361 break;
2362 case '?':
2363 /* getopt_long already printed an error message. */
2364 return 1;
2365 default:
2366 abort();
2367 }
2368 }
2369
2370 for (auto i = optind; i < argc; ++i) {
2371 load_instructions(argv[i]);
2372 }
2373
2374 if (!(out_file = fopen(out_file_name, "w"))) {
2375 fprintf(stderr, _("%s: can not open “%s” file (%s)\n"),
2376 short_program_name, out_file_name, strerror(errno));
2377 return 1;
2378 } else if (enabled(Actions::kInstructionName) ||
2379 enabled(Actions::kParseOperands)) {
2380 auto const_name = static_cast<char *>(malloc(strlen(out_file_name) + 10));
2381 strcpy(const_name, out_file_name);
2382 auto dot_position = strrchr(const_name, '.');
2383 if (!dot_position) {
2384 dot_position = strrchr(const_name, '\0');
2385 }
2386 strcpy(dot_position, "-consts.c");
2387 if (!(const_file = fopen(const_name, "w"))) {
2388 fprintf(stderr, _("%s: can not open “%s” file (%s)\n"),
2389 short_program_name, const_name, strerror(errno));
2390 return 1;
2391 }
2392 free(const_name);
2393 }
2394
2395 if (enabled(Actions::kInstructionName) ||
2396 enabled(Actions::kParseOperands)) {
2397 print_consts();
2398
2399 if (out_file == const_file) {
2400 for (auto i = 0; i < 80; ++i) {
2401 fputc('#', out_file);
2402 }
2403 fputc('\n', out_file);
2404 }
2405 }
2406
2407 if (ia32_mode) {
2408 fprintf(out_file, "%%%%{\n"
2409 " machine decode_x86_32;\n"
2410 " alphtype unsigned char;\n"
2411 "");
2412 } else {
2413 fprintf(out_file, "END(%%%%{\n"
2414 " machine decode_x86_64;\n"
2415 " alphtype unsigned char;\n"
2416 "");
2417 }
2418
2419 print_common_decoding();
2420
2421 if (enabled(Actions::kInstructionName)) {
2422 print_name_actions();
2423 }
2424
2425 fprintf(out_file, "\n one_instruction =");
2426
2427 print_one_instruction_definition();
2428
2429 fprintf(out_file, ");\n"
2430 "}%%%%\n"
2431 "");
2432 return 0;
2433 }
OLDNEW
« no previous file with comments | « src/trusted/validator_ragel/decoder_test_one_file.sh ('k') | src/trusted/validator_ragel/gen-decoder-flags.C » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698