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