1#!/bin/awk -f 2# SPDX-License-Identifier: GPL-2.0 3# gen-insn-attr-x86.awk: Instruction attribute table generator 4# Written by Masami Hiramatsu <mhiramat@redhat.com> 5# 6# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c 7 8# Awk implementation sanity check 9function check_awk_implement() { 10 if (sprintf("%x", 0) != "0") 11 return "Your awk has a printf-format problem." 12 return "" 13} 14 15# Clear working vars 16function clear_vars() { 17 delete table 18 delete lptable2 19 delete lptable1 20 delete lptable3 21 eid = -1 # escape id 22 gid = -1 # group id 23 aid = -1 # AVX id 24 xopid = -1 # XOP id 25 tname = "" 26} 27 28BEGIN { 29 # Implementation error checking 30 awkchecked = check_awk_implement() 31 if (awkchecked != "") { 32 print "Error: " awkchecked > "/dev/stderr" 33 print "Please try to use gawk." > "/dev/stderr" 34 exit 1 35 } 36 37 # Setup generating tables 38 print "/* x86 opcode map generated from x86-opcode-map.txt */" 39 print "/* Do not change this code. */\n" 40 ggid = 1 41 geid = 1 42 gaid = 0 43 gxopid = 0 44 delete etable 45 delete gtable 46 delete atable 47 delete xoptable 48 49 opnd_expr = "^[A-Za-z/]" 50 ext_expr = "^\\(" 51 sep_expr = "^\\|$" 52 group_expr = "^Grp[0-9A-Za-z]+" 53 54 imm_expr = "^[IJAOL][a-z]" 55 imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" 56 imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" 57 imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" 58 imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" 59 imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" 60 imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" 61 imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" 62 imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" 63 imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" 64 imm_flag["Ob"] = "INAT_MOFFSET" 65 imm_flag["Ov"] = "INAT_MOFFSET" 66 imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" 67 imm_flag["Lo"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" 68 69 modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" 70 force64_expr = "\\([df]64\\)" 71 invalid64_expr = "\\(i64\\)" 72 only64_expr = "\\(o64\\)" 73 rex_expr = "^((REX(\\.[XRWB]+)+)|(REX$))" 74 rex2_expr = "\\(REX2\\)" 75 no_rex2_expr = "\\(!REX2\\)" 76 fpu_expr = "^ESC" # TODO 77 78 lprefix1_expr = "\\((66|!F3)\\)" 79 lprefix2_expr = "\\(F3\\)" 80 lprefix3_expr = "\\((F2|!F3|66&F2)\\)" 81 lprefix_expr = "\\((66|F2|F3)\\)" 82 max_lprefix = 4 83 84 # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript 85 # accepts VEX prefix 86 vexok_opcode_expr = "^[vk].*" 87 vexok_expr = "\\(v1\\)" 88 # All opcodes with (v) superscript supports *only* VEX prefix 89 vexonly_expr = "\\(v\\)" 90 # All opcodes with (ev) superscript supports *only* EVEX prefix 91 evexonly_expr = "\\(ev\\)" 92 # (es) is the same as (ev) but also "SCALABLE" i.e. W and pp determine operand size 93 evex_scalable_expr = "\\(es\\)" 94 # All opcodes in XOP table or with (xop) superscript accept XOP prefix 95 xopok_expr = "\\(xop\\)" 96 97 prefix_expr = "\\(Prefix\\)" 98 prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" 99 prefix_num["REPNE"] = "INAT_PFX_REPNE" 100 prefix_num["REP/REPE"] = "INAT_PFX_REPE" 101 prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" 102 prefix_num["XRELEASE"] = "INAT_PFX_REPE" 103 prefix_num["LOCK"] = "INAT_PFX_LOCK" 104 prefix_num["SEG=CS"] = "INAT_PFX_CS" 105 prefix_num["SEG=DS"] = "INAT_PFX_DS" 106 prefix_num["SEG=ES"] = "INAT_PFX_ES" 107 prefix_num["SEG=FS"] = "INAT_PFX_FS" 108 prefix_num["SEG=GS"] = "INAT_PFX_GS" 109 prefix_num["SEG=SS"] = "INAT_PFX_SS" 110 prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" 111 prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" 112 prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" 113 prefix_num["EVEX"] = "INAT_PFX_EVEX" 114 prefix_num["REX2"] = "INAT_PFX_REX2" 115 prefix_num["XOP"] = "INAT_PFX_XOP" 116 117 clear_vars() 118} 119 120function semantic_error(msg) { 121 print "Semantic error at " NR ": " msg > "/dev/stderr" 122 exit 1 123} 124 125function debug(msg) { 126 print "DEBUG: " msg 127} 128 129function array_size(arr, i,c) { 130 c = 0 131 for (i in arr) 132 c++ 133 return c 134} 135 136/^Table:/ { 137 print "/* " $0 " */" 138 if (tname != "") 139 semantic_error("Hit Table: before EndTable:."); 140} 141 142/^Referrer:/ { 143 if (NF != 1) { 144 # escape opcode table 145 ref = "" 146 for (i = 2; i <= NF; i++) 147 ref = ref $i 148 eid = escape[ref] 149 tname = sprintf("inat_escape_table_%d", eid) 150 } 151} 152 153/^AVXcode:/ { 154 if (NF != 1) { 155 # AVX/escape opcode table 156 aid = $2 157 xopid = -1 158 if (gaid <= aid) 159 gaid = aid + 1 160 if (tname == "") # AVX only opcode table 161 tname = sprintf("inat_avx_table_%d", $2) 162 } 163 if (aid == -1 && eid == -1) # primary opcode table 164 tname = "inat_primary_table" 165} 166 167/^XOPcode:/ { 168 if (NF != 1) { 169 # XOP opcode table 170 xopid = $2 171 aid = -1 172 if (gxopid <= xopid) 173 gxopid = xopid + 1 174 if (tname == "") # XOP only opcode table 175 tname = sprintf("inat_xop_table_%d", $2) 176 } 177 if (xopid == -1 && eid == -1) # primary opcode table 178 tname = "inat_primary_table" 179} 180 181/^GrpTable:/ { 182 print "/* " $0 " */" 183 if (!($2 in group)) 184 semantic_error("No group: " $2 ) 185 gid = group[$2] 186 tname = "inat_group_table_" gid 187} 188 189function print_table(tbl,name,fmt,n) 190{ 191 print "const insn_attr_t " name " = {" 192 for (i = 0; i < n; i++) { 193 id = sprintf(fmt, i) 194 if (tbl[id]) 195 print " [" id "] = " tbl[id] "," 196 } 197 print "};" 198} 199 200/^EndTable/ { 201 if (gid != -1) { 202 # print group tables 203 if (array_size(table) != 0) { 204 print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", 205 "0x%x", 8) 206 gtable[gid,0] = tname 207 } 208 if (array_size(lptable1) != 0) { 209 print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", 210 "0x%x", 8) 211 gtable[gid,1] = tname "_1" 212 } 213 if (array_size(lptable2) != 0) { 214 print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", 215 "0x%x", 8) 216 gtable[gid,2] = tname "_2" 217 } 218 if (array_size(lptable3) != 0) { 219 print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", 220 "0x%x", 8) 221 gtable[gid,3] = tname "_3" 222 } 223 } else { 224 # print primary/escaped tables 225 if (array_size(table) != 0) { 226 print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", 227 "0x%02x", 256) 228 etable[eid,0] = tname 229 if (aid >= 0) 230 atable[aid,0] = tname 231 else if (xopid >= 0) 232 xoptable[xopid] = tname 233 } 234 if (array_size(lptable1) != 0) { 235 print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", 236 "0x%02x", 256) 237 etable[eid,1] = tname "_1" 238 if (aid >= 0) 239 atable[aid,1] = tname "_1" 240 } 241 if (array_size(lptable2) != 0) { 242 print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", 243 "0x%02x", 256) 244 etable[eid,2] = tname "_2" 245 if (aid >= 0) 246 atable[aid,2] = tname "_2" 247 } 248 if (array_size(lptable3) != 0) { 249 print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", 250 "0x%02x", 256) 251 etable[eid,3] = tname "_3" 252 if (aid >= 0) 253 atable[aid,3] = tname "_3" 254 } 255 } 256 print "" 257 clear_vars() 258} 259 260function add_flags(old,new) { 261 if (old && new) 262 return old " | " new 263 else if (old) 264 return old 265 else 266 return new 267} 268 269# convert operands to flags. 270function convert_operands(count,opnd, i,j,imm,mod) 271{ 272 imm = null 273 mod = null 274 for (j = 1; j <= count; j++) { 275 i = opnd[j] 276 if (match(i, imm_expr) == 1) { 277 if (!imm_flag[i]) 278 semantic_error("Unknown imm opnd: " i) 279 if (imm) { 280 if (i != "Ib") 281 semantic_error("Second IMM error") 282 imm = add_flags(imm, "INAT_SCNDIMM") 283 } else 284 imm = imm_flag[i] 285 } else if (match(i, modrm_expr)) 286 mod = "INAT_MODRM" 287 } 288 return add_flags(imm, mod) 289} 290 291/^[0-9a-f]+:/ { 292 if (NR == 1) 293 next 294 # get index 295 idx = "0x" substr($1, 1, index($1,":") - 1) 296 if (idx in table) 297 semantic_error("Redefine " idx " in " tname) 298 299 # check if escaped opcode 300 if ("escape" == $2) { 301 if ($3 != "#") 302 semantic_error("No escaped name") 303 ref = "" 304 for (i = 4; i <= NF; i++) 305 ref = ref $i 306 if (ref in escape) 307 semantic_error("Redefine escape (" ref ")") 308 escape[ref] = geid 309 geid++ 310 table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" 311 next 312 } 313 314 variant = null 315 # converts 316 i = 2 317 while (i <= NF) { 318 opcode = $(i++) 319 delete opnds 320 ext = null 321 flags = null 322 opnd = null 323 # parse one opcode 324 if (match($i, opnd_expr)) { 325 opnd = $i 326 count = split($(i++), opnds, ",") 327 flags = convert_operands(count, opnds) 328 } 329 if (match($i, ext_expr)) 330 ext = $(i++) 331 if (match($i, sep_expr)) 332 i++ 333 else if (i < NF) 334 semantic_error($i " is not a separator") 335 336 # check if group opcode 337 if (match(opcode, group_expr)) { 338 if (!(opcode in group)) { 339 group[opcode] = ggid 340 ggid++ 341 } 342 flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") 343 } 344 # check force(or default) 64bit 345 if (match(ext, force64_expr)) 346 flags = add_flags(flags, "INAT_FORCE64") 347 348 # check invalid in 64-bit (and no only64) 349 if (match(ext, invalid64_expr) && 350 !match($0, only64_expr)) 351 flags = add_flags(flags, "INAT_INV64") 352 353 # check REX2 not allowed 354 if (match(ext, no_rex2_expr)) 355 flags = add_flags(flags, "INAT_NO_REX2") 356 357 # check REX prefix 358 if (match(opcode, rex_expr)) 359 flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") 360 361 # check coprocessor escape : TODO 362 if (match(opcode, fpu_expr)) 363 flags = add_flags(flags, "INAT_MODRM") 364 365 # check VEX codes 366 if (match(ext, evexonly_expr)) 367 flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") 368 else if (match(ext, evex_scalable_expr)) 369 flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY | INAT_EVEX_SCALABLE") 370 else if (match(ext, vexonly_expr)) 371 flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") 372 else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) 373 flags = add_flags(flags, "INAT_VEXOK") 374 else if (match(ext, xopok_expr) || xopid >= 0) 375 flags = add_flags(flags, "INAT_XOPOK") 376 377 # check prefixes 378 if (match(ext, prefix_expr)) { 379 if (!prefix_num[opcode]) 380 semantic_error("Unknown prefix: " opcode) 381 flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") 382 } 383 if (length(flags) == 0) 384 continue 385 # check if last prefix 386 if (match(ext, lprefix1_expr)) { 387 lptable1[idx] = add_flags(lptable1[idx],flags) 388 variant = "INAT_VARIANT" 389 } 390 if (match(ext, lprefix2_expr)) { 391 lptable2[idx] = add_flags(lptable2[idx],flags) 392 variant = "INAT_VARIANT" 393 } 394 if (match(ext, lprefix3_expr)) { 395 lptable3[idx] = add_flags(lptable3[idx],flags) 396 variant = "INAT_VARIANT" 397 } 398 if (match(ext, rex2_expr)) 399 table[idx] = add_flags(table[idx], "INAT_REX2_VARIANT") 400 if (!match(ext, lprefix_expr)){ 401 table[idx] = add_flags(table[idx],flags) 402 } 403 } 404 if (variant) 405 table[idx] = add_flags(table[idx],variant) 406} 407 408END { 409 if (awkchecked != "") 410 exit 1 411 412 print "#ifndef __BOOT_COMPRESSED\n" 413 414 # print escape opcode map's array 415 print "/* Escape opcode map array */" 416 print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ 417 "[INAT_LSTPFX_MAX + 1] = {" 418 for (i = 0; i < geid; i++) 419 for (j = 0; j < max_lprefix; j++) 420 if (etable[i,j]) 421 print " ["i"]["j"] = "etable[i,j]"," 422 print "};\n" 423 # print group opcode map's array 424 print "/* Group opcode map array */" 425 print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ 426 "[INAT_LSTPFX_MAX + 1] = {" 427 for (i = 0; i < ggid; i++) 428 for (j = 0; j < max_lprefix; j++) 429 if (gtable[i,j]) 430 print " ["i"]["j"] = "gtable[i,j]"," 431 print "};\n" 432 # print AVX opcode map's array 433 print "/* AVX opcode map array */" 434 print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ 435 "[INAT_LSTPFX_MAX + 1] = {" 436 for (i = 0; i < gaid; i++) 437 for (j = 0; j < max_lprefix; j++) 438 if (atable[i,j]) 439 print " ["i"]["j"] = "atable[i,j]"," 440 print "};\n" 441 442 print "/* XOP opcode map array */" 443 print "const insn_attr_t * const inat_xop_tables[X86_XOP_M_MAX - X86_XOP_M_MIN + 1]" \ 444 " = {" 445 for (i = 0; i < gxopid; i++) 446 if (xoptable[i]) 447 print " ["i"] = "xoptable[i]"," 448 print "};" 449 450 print "#else /* !__BOOT_COMPRESSED */\n" 451 452 print "/* Escape opcode map array */" 453 print "static const insn_attr_t *inat_escape_tables[INAT_ESC_MAX + 1]" \ 454 "[INAT_LSTPFX_MAX + 1];" 455 print "" 456 457 print "/* Group opcode map array */" 458 print "static const insn_attr_t *inat_group_tables[INAT_GRP_MAX + 1]"\ 459 "[INAT_LSTPFX_MAX + 1];" 460 print "" 461 462 print "/* AVX opcode map array */" 463 print "static const insn_attr_t *inat_avx_tables[X86_VEX_M_MAX + 1]"\ 464 "[INAT_LSTPFX_MAX + 1];" 465 print "" 466 467 print "/* XOP opcode map array */" 468 print "static const insn_attr_t *inat_xop_tables[X86_XOP_M_MAX - X86_XOP_M_MIN + 1];" 469 print "" 470 471 print "static void inat_init_tables(void)" 472 print "{" 473 474 # print escape opcode map's array 475 print "\t/* Print Escape opcode map array */" 476 for (i = 0; i < geid; i++) 477 for (j = 0; j < max_lprefix; j++) 478 if (etable[i,j]) 479 print "\tinat_escape_tables["i"]["j"] = "etable[i,j]";" 480 print "" 481 482 # print group opcode map's array 483 print "\t/* Print Group opcode map array */" 484 for (i = 0; i < ggid; i++) 485 for (j = 0; j < max_lprefix; j++) 486 if (gtable[i,j]) 487 print "\tinat_group_tables["i"]["j"] = "gtable[i,j]";" 488 print "" 489 # print AVX opcode map's array 490 print "\t/* Print AVX opcode map array */" 491 for (i = 0; i < gaid; i++) 492 for (j = 0; j < max_lprefix; j++) 493 if (atable[i,j]) 494 print "\tinat_avx_tables["i"]["j"] = "atable[i,j]";" 495 496 print "" 497 print "\t/* Print XOP opcode map array */" 498 for (i = 0; i < gxopid; i++) 499 if (xoptable[i]) 500 print "\tinat_xop_tables["i"] = "xoptable[i]";" 501 502 print "}" 503 print "#endif" 504} 505 506