/contrib/binutils/opcodes/i386-gen.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 394 lines · 270 code · 84 blank · 40 comment · 67 complexity · fdb83205f96906fe88b09871cabc9c8e MD5 · raw file

  1. /* Copyright 2007 Free Software Foundation, Inc.
  2. This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include "getopt.h"
  19. #include "libiberty.h"
  20. #include "safe-ctype.h"
  21. #include "i386-opc.h"
  22. #include <libintl.h>
  23. #define _(String) gettext (String)
  24. static const char *program_name = NULL;
  25. static int debug = 0;
  26. static void
  27. fail (const char *message, ...)
  28. {
  29. va_list args;
  30. va_start (args, message);
  31. fprintf (stderr, _("%s: Error: "), program_name);
  32. vfprintf (stderr, message, args);
  33. va_end (args);
  34. xexit (1);
  35. }
  36. /* Remove leading white spaces. */
  37. static char *
  38. remove_leading_whitespaces (char *str)
  39. {
  40. while (ISSPACE (*str))
  41. str++;
  42. return str;
  43. }
  44. /* Remove trailing white spaces. */
  45. static void
  46. remove_trailing_whitespaces (char *str)
  47. {
  48. size_t last = strlen (str);
  49. if (last == 0)
  50. return;
  51. do
  52. {
  53. last--;
  54. if (ISSPACE (str [last]))
  55. str[last] = '\0';
  56. else
  57. break;
  58. }
  59. while (last != 0);
  60. }
  61. /* Find next field separated by '.' and terminate it. Return a
  62. pointer to the one after it. */
  63. static char *
  64. next_field (char *str, char **next)
  65. {
  66. char *p;
  67. p = remove_leading_whitespaces (str);
  68. for (str = p; *str != ',' && *str != '\0'; str++);
  69. *str = '\0';
  70. remove_trailing_whitespaces (p);
  71. *next = str + 1;
  72. return p;
  73. }
  74. static void
  75. process_i386_opcodes (void)
  76. {
  77. FILE *fp = fopen ("i386-opc.tbl", "r");
  78. char buf[2048];
  79. unsigned int i;
  80. char *str, *p, *last;
  81. char *name, *operands, *base_opcode, *extension_opcode;
  82. char *cpu_flags, *opcode_modifier, *operand_types [MAX_OPERANDS];
  83. if (fp == NULL)
  84. fail (_("can't find i386-opc.tbl for reading\n"));
  85. printf ("\n/* i386 opcode table. */\n\n");
  86. printf ("const template i386_optab[] =\n{\n");
  87. while (!feof (fp))
  88. {
  89. if (fgets (buf, sizeof (buf), fp) == NULL)
  90. break;
  91. p = remove_leading_whitespaces (buf);
  92. /* Skip comments. */
  93. str = strstr (p, "//");
  94. if (str != NULL)
  95. str[0] = '\0';
  96. /* Remove trailing white spaces. */
  97. remove_trailing_whitespaces (p);
  98. switch (p[0])
  99. {
  100. case '#':
  101. printf ("%s\n", p);
  102. case '\0':
  103. continue;
  104. break;
  105. default:
  106. break;
  107. }
  108. last = p + strlen (p);
  109. /* Find name. */
  110. name = next_field (p, &str);
  111. if (str >= last)
  112. abort ();
  113. /* Find number of operands. */
  114. operands = next_field (str, &str);
  115. if (str >= last)
  116. abort ();
  117. /* Find base_opcode. */
  118. base_opcode = next_field (str, &str);
  119. if (str >= last)
  120. abort ();
  121. /* Find extension_opcode. */
  122. extension_opcode = next_field (str, &str);
  123. if (str >= last)
  124. abort ();
  125. /* Find cpu_flags. */
  126. cpu_flags = next_field (str, &str);
  127. if (str >= last)
  128. abort ();
  129. /* Find opcode_modifier. */
  130. opcode_modifier = next_field (str, &str);
  131. if (str >= last)
  132. abort ();
  133. /* Remove the first {. */
  134. str = remove_leading_whitespaces (str);
  135. if (*str != '{')
  136. abort ();
  137. str = remove_leading_whitespaces (str + 1);
  138. i = strlen (str);
  139. /* There are at least "X}". */
  140. if (i < 2)
  141. abort ();
  142. /* Remove trailing white spaces and }. */
  143. do
  144. {
  145. i--;
  146. if (ISSPACE (str[i]) || str[i] == '}')
  147. str[i] = '\0';
  148. else
  149. break;
  150. }
  151. while (i != 0);
  152. last = str + i;
  153. /* Find operand_types. */
  154. for (i = 0; i < ARRAY_SIZE (operand_types); i++)
  155. {
  156. if (str >= last)
  157. {
  158. operand_types [i] = NULL;
  159. break;
  160. }
  161. operand_types [i] = next_field (str, &str);
  162. if (*operand_types[i] == '0')
  163. {
  164. if (i != 0)
  165. operand_types[i] = NULL;
  166. break;
  167. }
  168. }
  169. printf (" { \"%s\", %s, %s, %s, %s,\n",
  170. name, operands, base_opcode, extension_opcode,
  171. cpu_flags);
  172. printf (" %s,\n", opcode_modifier);
  173. printf (" { ");
  174. for (i = 0; i < ARRAY_SIZE (operand_types); i++)
  175. {
  176. if (operand_types[i] == NULL
  177. || *operand_types[i] == '0')
  178. {
  179. if (i == 0)
  180. printf ("0");
  181. break;
  182. }
  183. if (i != 0)
  184. printf (",\n ");
  185. printf ("%s", operand_types[i]);
  186. }
  187. printf (" } },\n");
  188. }
  189. printf (" { NULL, 0, 0, 0, 0, 0, { 0 } }\n");
  190. printf ("};\n");
  191. }
  192. static void
  193. process_i386_registers (void)
  194. {
  195. FILE *fp = fopen ("i386-reg.tbl", "r");
  196. char buf[2048];
  197. char *str, *p, *last;
  198. char *reg_name, *reg_type, *reg_flags, *reg_num;
  199. if (fp == NULL)
  200. fail (_("can't find i386-reg.tbl for reading\n"));
  201. printf ("\n/* i386 register table. */\n\n");
  202. printf ("const reg_entry i386_regtab[] =\n{\n");
  203. while (!feof (fp))
  204. {
  205. if (fgets (buf, sizeof (buf), fp) == NULL)
  206. break;
  207. p = remove_leading_whitespaces (buf);
  208. /* Skip comments. */
  209. str = strstr (p, "//");
  210. if (str != NULL)
  211. str[0] = '\0';
  212. /* Remove trailing white spaces. */
  213. remove_trailing_whitespaces (p);
  214. switch (p[0])
  215. {
  216. case '#':
  217. printf ("%s\n", p);
  218. case '\0':
  219. continue;
  220. break;
  221. default:
  222. break;
  223. }
  224. last = p + strlen (p);
  225. /* Find reg_name. */
  226. reg_name = next_field (p, &str);
  227. if (str >= last)
  228. abort ();
  229. /* Find reg_type. */
  230. reg_type = next_field (str, &str);
  231. if (str >= last)
  232. abort ();
  233. /* Find reg_flags. */
  234. reg_flags = next_field (str, &str);
  235. if (str >= last)
  236. abort ();
  237. /* Find reg_num. */
  238. reg_num = next_field (str, &str);
  239. printf (" { \"%s\", %s, %s, %s },\n",
  240. reg_name, reg_type, reg_flags, reg_num);
  241. }
  242. printf ("};\n");
  243. printf ("\nconst unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n");
  244. }
  245. /* Program options. */
  246. #define OPTION_SRCDIR 200
  247. struct option long_options[] =
  248. {
  249. {"srcdir", required_argument, NULL, OPTION_SRCDIR},
  250. {"debug", no_argument, NULL, 'd'},
  251. {"version", no_argument, NULL, 'V'},
  252. {"help", no_argument, NULL, 'h'},
  253. {0, no_argument, NULL, 0}
  254. };
  255. static void
  256. print_version (void)
  257. {
  258. printf ("%s: version 1.0\n", program_name);
  259. xexit (0);
  260. }
  261. static void
  262. usage (FILE * stream, int status)
  263. {
  264. fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n",
  265. program_name);
  266. xexit (status);
  267. }
  268. int
  269. main (int argc, char **argv)
  270. {
  271. extern int chdir (char *);
  272. char *srcdir = NULL;
  273. int c;
  274. program_name = *argv;
  275. xmalloc_set_program_name (program_name);
  276. while ((c = getopt_long (argc, argv, "vVdh", long_options, 0)) != EOF)
  277. switch (c)
  278. {
  279. case OPTION_SRCDIR:
  280. srcdir = optarg;
  281. break;
  282. case 'V':
  283. case 'v':
  284. print_version ();
  285. break;
  286. case 'd':
  287. debug = 1;
  288. break;
  289. case 'h':
  290. case '?':
  291. usage (stderr, 0);
  292. default:
  293. case 0:
  294. break;
  295. }
  296. if (optind != argc)
  297. usage (stdout, 1);
  298. if (srcdir != NULL)
  299. if (chdir (srcdir) != 0)
  300. fail (_("unable to change directory to \"%s\", errno = %s\n"),
  301. srcdir, strerror (errno));
  302. printf ("/* This file is automatically generated by i386-gen. Do not edit! */\n");
  303. process_i386_opcodes ();
  304. process_i386_registers ();
  305. exit (0);
  306. }