1214571Sdim/* Copyright 2007 Free Software Foundation, Inc. 2214571Sdim 3214571Sdim This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger. 4214571Sdim 5214571Sdim This program is free software; you can redistribute it and/or modify 6214571Sdim it under the terms of the GNU General Public License as published by 7214571Sdim the Free Software Foundation; either version 2 of the License, or 8214571Sdim (at your option) any later version. 9214571Sdim 10214571Sdim This program is distributed in the hope that it will be useful, 11214571Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 12214571Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13214571Sdim GNU General Public License for more details. 14214571Sdim 15214571Sdim You should have received a copy of the GNU General Public License 16214571Sdim along with this program; if not, write to the Free Software 17214571Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 18214571Sdim 19214571Sdim#include <stdio.h> 20214571Sdim#include <stdlib.h> 21214571Sdim#include <string.h> 22214571Sdim#include <errno.h> 23214571Sdim#include "getopt.h" 24214571Sdim#include "libiberty.h" 25214571Sdim#include "safe-ctype.h" 26214571Sdim 27214571Sdim#include "i386-opc.h" 28214571Sdim 29214571Sdim#include <libintl.h> 30214571Sdim#define _(String) gettext (String) 31214571Sdim 32214571Sdimstatic const char *program_name = NULL; 33214571Sdimstatic int debug = 0; 34214571Sdim 35214571Sdimstatic void 36214571Sdimfail (const char *message, ...) 37214571Sdim{ 38214571Sdim va_list args; 39214571Sdim 40214571Sdim va_start (args, message); 41214571Sdim fprintf (stderr, _("%s: Error: "), program_name); 42214571Sdim vfprintf (stderr, message, args); 43214571Sdim va_end (args); 44214571Sdim xexit (1); 45214571Sdim} 46214571Sdim 47214571Sdim/* Remove leading white spaces. */ 48214571Sdim 49214571Sdimstatic char * 50214571Sdimremove_leading_whitespaces (char *str) 51214571Sdim{ 52214571Sdim while (ISSPACE (*str)) 53214571Sdim str++; 54214571Sdim return str; 55214571Sdim} 56214571Sdim 57214571Sdim/* Remove trailing white spaces. */ 58214571Sdim 59214571Sdimstatic void 60214571Sdimremove_trailing_whitespaces (char *str) 61214571Sdim{ 62214571Sdim size_t last = strlen (str); 63214571Sdim 64214571Sdim if (last == 0) 65214571Sdim return; 66214571Sdim 67214571Sdim do 68214571Sdim { 69214571Sdim last--; 70214571Sdim if (ISSPACE (str [last])) 71214571Sdim str[last] = '\0'; 72214571Sdim else 73214571Sdim break; 74214571Sdim } 75214571Sdim while (last != 0); 76214571Sdim} 77214571Sdim 78214571Sdim/* Find next field separated by '.' and terminate it. Return a 79214571Sdim pointer to the one after it. */ 80214571Sdim 81214571Sdimstatic char * 82214571Sdimnext_field (char *str, char **next) 83214571Sdim{ 84214571Sdim char *p; 85214571Sdim 86214571Sdim p = remove_leading_whitespaces (str); 87214571Sdim for (str = p; *str != ',' && *str != '\0'; str++); 88214571Sdim 89214571Sdim *str = '\0'; 90214571Sdim remove_trailing_whitespaces (p); 91214571Sdim 92214571Sdim *next = str + 1; 93214571Sdim 94214571Sdim return p; 95214571Sdim} 96214571Sdim 97214571Sdimstatic void 98214571Sdimprocess_i386_opcodes (void) 99214571Sdim{ 100214571Sdim FILE *fp = fopen ("i386-opc.tbl", "r"); 101214571Sdim char buf[2048]; 102214571Sdim unsigned int i; 103214571Sdim char *str, *p, *last; 104214571Sdim char *name, *operands, *base_opcode, *extension_opcode; 105214571Sdim char *cpu_flags, *opcode_modifier, *operand_types [MAX_OPERANDS]; 106214571Sdim 107214571Sdim if (fp == NULL) 108214571Sdim fail (_("can't find i386-opc.tbl for reading\n")); 109214571Sdim 110214571Sdim printf ("\n/* i386 opcode table. */\n\n"); 111214571Sdim printf ("const template i386_optab[] =\n{\n"); 112214571Sdim 113214571Sdim while (!feof (fp)) 114214571Sdim { 115214571Sdim if (fgets (buf, sizeof (buf), fp) == NULL) 116214571Sdim break; 117214571Sdim 118214571Sdim p = remove_leading_whitespaces (buf); 119214571Sdim 120214571Sdim /* Skip comments. */ 121214571Sdim str = strstr (p, "//"); 122214571Sdim if (str != NULL) 123214571Sdim str[0] = '\0'; 124214571Sdim 125214571Sdim /* Remove trailing white spaces. */ 126214571Sdim remove_trailing_whitespaces (p); 127214571Sdim 128214571Sdim switch (p[0]) 129214571Sdim { 130214571Sdim case '#': 131214571Sdim printf ("%s\n", p); 132214571Sdim case '\0': 133214571Sdim continue; 134214571Sdim break; 135214571Sdim default: 136214571Sdim break; 137214571Sdim } 138214571Sdim 139214571Sdim last = p + strlen (p); 140214571Sdim 141214571Sdim /* Find name. */ 142214571Sdim name = next_field (p, &str); 143214571Sdim 144214571Sdim if (str >= last) 145214571Sdim abort (); 146214571Sdim 147214571Sdim /* Find number of operands. */ 148214571Sdim operands = next_field (str, &str); 149214571Sdim 150214571Sdim if (str >= last) 151214571Sdim abort (); 152214571Sdim 153214571Sdim /* Find base_opcode. */ 154214571Sdim base_opcode = next_field (str, &str); 155214571Sdim 156214571Sdim if (str >= last) 157214571Sdim abort (); 158214571Sdim 159214571Sdim /* Find extension_opcode. */ 160214571Sdim extension_opcode = next_field (str, &str); 161214571Sdim 162214571Sdim if (str >= last) 163214571Sdim abort (); 164214571Sdim 165214571Sdim /* Find cpu_flags. */ 166214571Sdim cpu_flags = next_field (str, &str); 167214571Sdim 168214571Sdim if (str >= last) 169214571Sdim abort (); 170214571Sdim 171214571Sdim /* Find opcode_modifier. */ 172214571Sdim opcode_modifier = next_field (str, &str); 173214571Sdim 174214571Sdim if (str >= last) 175214571Sdim abort (); 176214571Sdim 177214571Sdim /* Remove the first {. */ 178214571Sdim str = remove_leading_whitespaces (str); 179214571Sdim if (*str != '{') 180214571Sdim abort (); 181214571Sdim str = remove_leading_whitespaces (str + 1); 182214571Sdim 183214571Sdim i = strlen (str); 184214571Sdim 185214571Sdim /* There are at least "X}". */ 186214571Sdim if (i < 2) 187214571Sdim abort (); 188214571Sdim 189214571Sdim /* Remove trailing white spaces and }. */ 190214571Sdim do 191214571Sdim { 192214571Sdim i--; 193214571Sdim if (ISSPACE (str[i]) || str[i] == '}') 194214571Sdim str[i] = '\0'; 195214571Sdim else 196214571Sdim break; 197214571Sdim } 198214571Sdim while (i != 0); 199214571Sdim 200214571Sdim last = str + i; 201214571Sdim 202214571Sdim /* Find operand_types. */ 203214571Sdim for (i = 0; i < ARRAY_SIZE (operand_types); i++) 204214571Sdim { 205214571Sdim if (str >= last) 206214571Sdim { 207214571Sdim operand_types [i] = NULL; 208214571Sdim break; 209214571Sdim } 210214571Sdim 211214571Sdim operand_types [i] = next_field (str, &str); 212214571Sdim if (*operand_types[i] == '0') 213214571Sdim { 214214571Sdim if (i != 0) 215214571Sdim operand_types[i] = NULL; 216214571Sdim break; 217214571Sdim } 218214571Sdim } 219214571Sdim 220214571Sdim printf (" { \"%s\", %s, %s, %s, %s,\n", 221214571Sdim name, operands, base_opcode, extension_opcode, 222214571Sdim cpu_flags); 223214571Sdim 224214571Sdim printf (" %s,\n", opcode_modifier); 225214571Sdim 226214571Sdim printf (" { "); 227214571Sdim 228214571Sdim for (i = 0; i < ARRAY_SIZE (operand_types); i++) 229214571Sdim { 230214571Sdim if (operand_types[i] == NULL 231214571Sdim || *operand_types[i] == '0') 232214571Sdim { 233214571Sdim if (i == 0) 234214571Sdim printf ("0"); 235214571Sdim break; 236214571Sdim } 237214571Sdim 238214571Sdim if (i != 0) 239214571Sdim printf (",\n "); 240214571Sdim 241214571Sdim printf ("%s", operand_types[i]); 242214571Sdim } 243214571Sdim printf (" } },\n"); 244214571Sdim } 245214571Sdim 246214571Sdim printf (" { NULL, 0, 0, 0, 0, 0, { 0 } }\n"); 247214571Sdim printf ("};\n"); 248214571Sdim} 249214571Sdim 250214571Sdimstatic void 251214571Sdimprocess_i386_registers (void) 252214571Sdim{ 253214571Sdim FILE *fp = fopen ("i386-reg.tbl", "r"); 254214571Sdim char buf[2048]; 255214571Sdim char *str, *p, *last; 256214571Sdim char *reg_name, *reg_type, *reg_flags, *reg_num; 257214571Sdim 258214571Sdim if (fp == NULL) 259214571Sdim fail (_("can't find i386-reg.tbl for reading\n")); 260214571Sdim 261214571Sdim printf ("\n/* i386 register table. */\n\n"); 262214571Sdim printf ("const reg_entry i386_regtab[] =\n{\n"); 263214571Sdim 264214571Sdim while (!feof (fp)) 265214571Sdim { 266214571Sdim if (fgets (buf, sizeof (buf), fp) == NULL) 267214571Sdim break; 268214571Sdim 269214571Sdim p = remove_leading_whitespaces (buf); 270214571Sdim 271214571Sdim /* Skip comments. */ 272214571Sdim str = strstr (p, "//"); 273214571Sdim if (str != NULL) 274214571Sdim str[0] = '\0'; 275214571Sdim 276214571Sdim /* Remove trailing white spaces. */ 277214571Sdim remove_trailing_whitespaces (p); 278214571Sdim 279214571Sdim switch (p[0]) 280214571Sdim { 281214571Sdim case '#': 282214571Sdim printf ("%s\n", p); 283214571Sdim case '\0': 284214571Sdim continue; 285214571Sdim break; 286214571Sdim default: 287214571Sdim break; 288214571Sdim } 289214571Sdim 290214571Sdim last = p + strlen (p); 291214571Sdim 292214571Sdim /* Find reg_name. */ 293214571Sdim reg_name = next_field (p, &str); 294214571Sdim 295214571Sdim if (str >= last) 296214571Sdim abort (); 297214571Sdim 298214571Sdim /* Find reg_type. */ 299214571Sdim reg_type = next_field (str, &str); 300214571Sdim 301214571Sdim if (str >= last) 302214571Sdim abort (); 303214571Sdim 304214571Sdim /* Find reg_flags. */ 305214571Sdim reg_flags = next_field (str, &str); 306214571Sdim 307214571Sdim if (str >= last) 308214571Sdim abort (); 309214571Sdim 310214571Sdim /* Find reg_num. */ 311214571Sdim reg_num = next_field (str, &str); 312214571Sdim 313214571Sdim printf (" { \"%s\", %s, %s, %s },\n", 314214571Sdim reg_name, reg_type, reg_flags, reg_num); 315214571Sdim } 316214571Sdim 317214571Sdim printf ("};\n"); 318214571Sdim 319214571Sdim printf ("\nconst unsigned int i386_regtab_size = ARRAY_SIZE (i386_regtab);\n"); 320214571Sdim} 321214571Sdim 322214571Sdim/* Program options. */ 323214571Sdim#define OPTION_SRCDIR 200 324214571Sdim 325214571Sdimstruct option long_options[] = 326214571Sdim{ 327214571Sdim {"srcdir", required_argument, NULL, OPTION_SRCDIR}, 328214571Sdim {"debug", no_argument, NULL, 'd'}, 329214571Sdim {"version", no_argument, NULL, 'V'}, 330214571Sdim {"help", no_argument, NULL, 'h'}, 331214571Sdim {0, no_argument, NULL, 0} 332214571Sdim}; 333214571Sdim 334214571Sdimstatic void 335214571Sdimprint_version (void) 336214571Sdim{ 337214571Sdim printf ("%s: version 1.0\n", program_name); 338214571Sdim xexit (0); 339214571Sdim} 340214571Sdim 341214571Sdimstatic void 342214571Sdimusage (FILE * stream, int status) 343214571Sdim{ 344214571Sdim fprintf (stream, "Usage: %s [-V | --version] [-d | --debug] [--srcdir=dirname] [--help]\n", 345214571Sdim program_name); 346214571Sdim xexit (status); 347214571Sdim} 348214571Sdim 349214571Sdimint 350214571Sdimmain (int argc, char **argv) 351214571Sdim{ 352214571Sdim extern int chdir (char *); 353214571Sdim char *srcdir = NULL; 354214571Sdim int c; 355214571Sdim 356214571Sdim program_name = *argv; 357214571Sdim xmalloc_set_program_name (program_name); 358214571Sdim 359214571Sdim while ((c = getopt_long (argc, argv, "vVdh", long_options, 0)) != EOF) 360214571Sdim switch (c) 361214571Sdim { 362214571Sdim case OPTION_SRCDIR: 363214571Sdim srcdir = optarg; 364214571Sdim break; 365214571Sdim case 'V': 366214571Sdim case 'v': 367214571Sdim print_version (); 368214571Sdim break; 369214571Sdim case 'd': 370214571Sdim debug = 1; 371214571Sdim break; 372214571Sdim case 'h': 373214571Sdim case '?': 374214571Sdim usage (stderr, 0); 375214571Sdim default: 376214571Sdim case 0: 377214571Sdim break; 378214571Sdim } 379214571Sdim 380214571Sdim if (optind != argc) 381214571Sdim usage (stdout, 1); 382214571Sdim 383214571Sdim if (srcdir != NULL) 384214571Sdim if (chdir (srcdir) != 0) 385214571Sdim fail (_("unable to change directory to \"%s\", errno = %s\n"), 386214571Sdim srcdir, strerror (errno)); 387214571Sdim 388214571Sdim printf ("/* This file is automatically generated by i386-gen. Do not edit! */\n"); 389214571Sdim 390214571Sdim process_i386_opcodes (); 391214571Sdim process_i386_registers (); 392214571Sdim 393214571Sdim exit (0); 394214571Sdim} 395