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