linux/arch/x86/tools/gen-insn-attr-x86.awk
<<
>>
Prefs
   1#!/bin/awk -f
   2# gen-insn-attr-x86.awk: Instruction attribute table generator
   3# Written by Masami Hiramatsu <mhiramat@redhat.com>
   4#
   5# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
   6
   7# Awk implementation sanity check
   8function check_awk_implement() {
   9        if (sprintf("%x", 0) != "0")
  10                return "Your awk has a printf-format problem."
  11        return ""
  12}
  13
  14# Clear working vars
  15function clear_vars() {
  16        delete table
  17        delete lptable2
  18        delete lptable1
  19        delete lptable3
  20        eid = -1 # escape id
  21        gid = -1 # group id
  22        aid = -1 # AVX id
  23        tname = ""
  24}
  25
  26BEGIN {
  27        # Implementation error checking
  28        awkchecked = check_awk_implement()
  29        if (awkchecked != "") {
  30                print "Error: " awkchecked > "/dev/stderr"
  31                print "Please try to use gawk." > "/dev/stderr"
  32                exit 1
  33        }
  34
  35        # Setup generating tables
  36        print "/* x86 opcode map generated from x86-opcode-map.txt */"
  37        print "/* Do not change this code. */\n"
  38        ggid = 1
  39        geid = 1
  40        gaid = 0
  41        delete etable
  42        delete gtable
  43        delete atable
  44
  45        opnd_expr = "^[A-Za-z/]"
  46        ext_expr = "^\\("
  47        sep_expr = "^\\|$"
  48        group_expr = "^Grp[0-9A-Za-z]+"
  49
  50        imm_expr = "^[IJAOL][a-z]"
  51        imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
  52        imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
  53        imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
  54        imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
  55        imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
  56        imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
  57        imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
  58        imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
  59        imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
  60        imm_flag["Ob"] = "INAT_MOFFSET"
  61        imm_flag["Ov"] = "INAT_MOFFSET"
  62        imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
  63
  64        modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
  65        force64_expr = "\\([df]64\\)"
  66        rex_expr = "^REX(\\.[XRWB]+)*"
  67        fpu_expr = "^ESC" # TODO
  68
  69        lprefix1_expr = "\\((66|!F3)\\)"
  70        lprefix2_expr = "\\(F3\\)"
  71        lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)"
  72        lprefix_expr = "\\((66|F2|F3)\\)"
  73        max_lprefix = 4
  74
  75        # All opcodes starting with lower-case 'v' or with (v1) superscript
  76        # accepts VEX prefix
  77        vexok_opcode_expr = "^v.*"
  78        vexok_expr = "\\(v1\\)"
  79        # All opcodes with (v) superscript supports *only* VEX prefix
  80        vexonly_expr = "\\(v\\)"
  81
  82        prefix_expr = "\\(Prefix\\)"
  83        prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
  84        prefix_num["REPNE"] = "INAT_PFX_REPNE"
  85        prefix_num["REP/REPE"] = "INAT_PFX_REPE"
  86        prefix_num["XACQUIRE"] = "INAT_PFX_REPNE"
  87        prefix_num["XRELEASE"] = "INAT_PFX_REPE"
  88        prefix_num["LOCK"] = "INAT_PFX_LOCK"
  89        prefix_num["SEG=CS"] = "INAT_PFX_CS"
  90        prefix_num["SEG=DS"] = "INAT_PFX_DS"
  91        prefix_num["SEG=ES"] = "INAT_PFX_ES"
  92        prefix_num["SEG=FS"] = "INAT_PFX_FS"
  93        prefix_num["SEG=GS"] = "INAT_PFX_GS"
  94        prefix_num["SEG=SS"] = "INAT_PFX_SS"
  95        prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
  96        prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
  97        prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
  98
  99        clear_vars()
 100}
 101
 102function semantic_error(msg) {
 103        print "Semantic error at " NR ": " msg > "/dev/stderr"
 104        exit 1
 105}
 106
 107function debug(msg) {
 108        print "DEBUG: " msg
 109}
 110
 111function array_size(arr,   i,c) {
 112        c = 0
 113        for (i in arr)
 114                c++
 115        return c
 116}
 117
 118/^Table:/ {
 119        print "/* " $0 " */"
 120        if (tname != "")
 121                semantic_error("Hit Table: before EndTable:.");
 122}
 123
 124/^Referrer:/ {
 125        if (NF != 1) {
 126                # escape opcode table
 127                ref = ""
 128                for (i = 2; i <= NF; i++)
 129                        ref = ref $i
 130                eid = escape[ref]
 131                tname = sprintf("inat_escape_table_%d", eid)
 132        }
 133}
 134
 135/^AVXcode:/ {
 136        if (NF != 1) {
 137                # AVX/escape opcode table
 138                aid = $2
 139                if (gaid <= aid)
 140                        gaid = aid + 1
 141                if (tname == "")        # AVX only opcode table
 142                        tname = sprintf("inat_avx_table_%d", $2)
 143        }
 144        if (aid == -1 && eid == -1)     # primary opcode table
 145                tname = "inat_primary_table"
 146}
 147
 148/^GrpTable:/ {
 149        print "/* " $0 " */"
 150        if (!($2 in group))
 151                semantic_error("No group: " $2 )
 152        gid = group[$2]
 153        tname = "inat_group_table_" gid
 154}
 155
 156function print_table(tbl,name,fmt,n)
 157{
 158        print "const insn_attr_t " name " = {"
 159        for (i = 0; i < n; i++) {
 160                id = sprintf(fmt, i)
 161                if (tbl[id])
 162                        print " [" id "] = " tbl[id] ","
 163        }
 164        print "};"
 165}
 166
 167/^EndTable/ {
 168        if (gid != -1) {
 169                # print group tables
 170                if (array_size(table) != 0) {
 171                        print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
 172                                    "0x%x", 8)
 173                        gtable[gid,0] = tname
 174                }
 175                if (array_size(lptable1) != 0) {
 176                        print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
 177                                    "0x%x", 8)
 178                        gtable[gid,1] = tname "_1"
 179                }
 180                if (array_size(lptable2) != 0) {
 181                        print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
 182                                    "0x%x", 8)
 183                        gtable[gid,2] = tname "_2"
 184                }
 185                if (array_size(lptable3) != 0) {
 186                        print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
 187                                    "0x%x", 8)
 188                        gtable[gid,3] = tname "_3"
 189                }
 190        } else {
 191                # print primary/escaped tables
 192                if (array_size(table) != 0) {
 193                        print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
 194                                    "0x%02x", 256)
 195                        etable[eid,0] = tname
 196                        if (aid >= 0)
 197                                atable[aid,0] = tname
 198                }
 199                if (array_size(lptable1) != 0) {
 200                        print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
 201                                    "0x%02x", 256)
 202                        etable[eid,1] = tname "_1"
 203                        if (aid >= 0)
 204                                atable[aid,1] = tname "_1"
 205                }
 206                if (array_size(lptable2) != 0) {
 207                        print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
 208                                    "0x%02x", 256)
 209                        etable[eid,2] = tname "_2"
 210                        if (aid >= 0)
 211                                atable[aid,2] = tname "_2"
 212                }
 213                if (array_size(lptable3) != 0) {
 214                        print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
 215                                    "0x%02x", 256)
 216                        etable[eid,3] = tname "_3"
 217                        if (aid >= 0)
 218                                atable[aid,3] = tname "_3"
 219                }
 220        }
 221        print ""
 222        clear_vars()
 223}
 224
 225function add_flags(old,new) {
 226        if (old && new)
 227                return old " | " new
 228        else if (old)
 229                return old
 230        else
 231                return new
 232}
 233
 234# convert operands to flags.
 235function convert_operands(count,opnd,       i,j,imm,mod)
 236{
 237        imm = null
 238        mod = null
 239        for (j = 1; j <= count; j++) {
 240                i = opnd[j]
 241                if (match(i, imm_expr) == 1) {
 242                        if (!imm_flag[i])
 243                                semantic_error("Unknown imm opnd: " i)
 244                        if (imm) {
 245                                if (i != "Ib")
 246                                        semantic_error("Second IMM error")
 247                                imm = add_flags(imm, "INAT_SCNDIMM")
 248                        } else
 249                                imm = imm_flag[i]
 250                } else if (match(i, modrm_expr))
 251                        mod = "INAT_MODRM"
 252        }
 253        return add_flags(imm, mod)
 254}
 255
 256/^[0-9a-f]+\:/ {
 257        if (NR == 1)
 258                next
 259        # get index
 260        idx = "0x" substr($1, 1, index($1,":") - 1)
 261        if (idx in table)
 262                semantic_error("Redefine " idx " in " tname)
 263
 264        # check if escaped opcode
 265        if ("escape" == $2) {
 266                if ($3 != "#")
 267                        semantic_error("No escaped name")
 268                ref = ""
 269                for (i = 4; i <= NF; i++)
 270                        ref = ref $i
 271                if (ref in escape)
 272                        semantic_error("Redefine escape (" ref ")")
 273                escape[ref] = geid
 274                geid++
 275                table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
 276                next
 277        }
 278
 279        variant = null
 280        # converts
 281        i = 2
 282        while (i <= NF) {
 283                opcode = $(i++)
 284                delete opnds
 285                ext = null
 286                flags = null
 287                opnd = null
 288                # parse one opcode
 289                if (match($i, opnd_expr)) {
 290                        opnd = $i
 291                        count = split($(i++), opnds, ",")
 292                        flags = convert_operands(count, opnds)
 293                }
 294                if (match($i, ext_expr))
 295                        ext = $(i++)
 296                if (match($i, sep_expr))
 297                        i++
 298                else if (i < NF)
 299                        semantic_error($i " is not a separator")
 300
 301                # check if group opcode
 302                if (match(opcode, group_expr)) {
 303                        if (!(opcode in group)) {
 304                                group[opcode] = ggid
 305                                ggid++
 306                        }
 307                        flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
 308                }
 309                # check force(or default) 64bit
 310                if (match(ext, force64_expr))
 311                        flags = add_flags(flags, "INAT_FORCE64")
 312
 313                # check REX prefix
 314                if (match(opcode, rex_expr))
 315                        flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
 316
 317                # check coprocessor escape : TODO
 318                if (match(opcode, fpu_expr))
 319                        flags = add_flags(flags, "INAT_MODRM")
 320
 321                # check VEX codes
 322                if (match(ext, vexonly_expr))
 323                        flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
 324                else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
 325                        flags = add_flags(flags, "INAT_VEXOK")
 326
 327                # check prefixes
 328                if (match(ext, prefix_expr)) {
 329                        if (!prefix_num[opcode])
 330                                semantic_error("Unknown prefix: " opcode)
 331                        flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
 332                }
 333                if (length(flags) == 0)
 334                        continue
 335                # check if last prefix
 336                if (match(ext, lprefix1_expr)) {
 337                        lptable1[idx] = add_flags(lptable1[idx],flags)
 338                        variant = "INAT_VARIANT"
 339                }
 340                if (match(ext, lprefix2_expr)) {
 341                        lptable2[idx] = add_flags(lptable2[idx],flags)
 342                        variant = "INAT_VARIANT"
 343                }
 344                if (match(ext, lprefix3_expr)) {
 345                        lptable3[idx] = add_flags(lptable3[idx],flags)
 346                        variant = "INAT_VARIANT"
 347                }
 348                if (!match(ext, lprefix_expr)){
 349                        table[idx] = add_flags(table[idx],flags)
 350                }
 351        }
 352        if (variant)
 353                table[idx] = add_flags(table[idx],variant)
 354}
 355
 356END {
 357        if (awkchecked != "")
 358                exit 1
 359        # print escape opcode map's array
 360        print "/* Escape opcode map array */"
 361        print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \
 362              "[INAT_LSTPFX_MAX + 1] = {"
 363        for (i = 0; i < geid; i++)
 364                for (j = 0; j < max_lprefix; j++)
 365                        if (etable[i,j])
 366                                print " ["i"]["j"] = "etable[i,j]","
 367        print "};\n"
 368        # print group opcode map's array
 369        print "/* Group opcode map array */"
 370        print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\
 371              "[INAT_LSTPFX_MAX + 1] = {"
 372        for (i = 0; i < ggid; i++)
 373                for (j = 0; j < max_lprefix; j++)
 374                        if (gtable[i,j])
 375                                print " ["i"]["j"] = "gtable[i,j]","
 376        print "};\n"
 377        # print AVX opcode map's array
 378        print "/* AVX opcode map array */"
 379        print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\
 380              "[INAT_LSTPFX_MAX + 1] = {"
 381        for (i = 0; i < gaid; i++)
 382                for (j = 0; j < max_lprefix; j++)
 383                        if (atable[i,j])
 384                                print " ["i"]["j"] = "atable[i,j]","
 385        print "};"
 386}
 387
 388