/* SPDX-License-Identifier: GPL-2.0 */
/*
* Generate opcode table initializers for the in - kernel disassembler .
*
* Copyright IBM Corp . 2017
*
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#define STRING_SIZE_MAX 20
struct insn_type {
unsigned char byte;
unsigned char mask;
char **format;
};
struct insn {
struct insn_type *type;
char opcode[STRING_SIZE_MAX];
char name[STRING_SIZE_MAX];
char upper[STRING_SIZE_MAX];
char format[STRING_SIZE_MAX];
unsigned int name_len;
};
struct insn_group {
struct insn_type *type;
int offset;
int count;
char opcode[2 ];
};
struct insn_format {
char *format;
int type;
};
struct gen_opcode {
struct insn *insn;
int nr;
struct insn_group *group;
int nr_groups;
};
/*
* Table of instruction format types . Each opcode is defined with at
* least one byte ( two nibbles ) , three nibbles , or two bytes ( four
* nibbles ) .
* The byte member of each instruction format type entry defines
* within which byte of an instruction the third ( and fourth ) nibble
* of an opcode can be found . The mask member is the and - mask that
* needs to be applied on this byte in order to get the third ( and
* fourth ) nibble of the opcode .
* The format array defines all instruction formats ( as defined in the
* Principles of Operation ) which have the same position of the opcode
* nibbles .
* A special case are instruction formats with 1 - byte opcodes . In this
* case the byte member always is zero , so that the mask is applied on
* the ( only ) byte that contains the opcode .
*/
static struct insn_type insn_type_table[] = {
{
.byte = 0 ,
.mask = 0 xff,
.format = (char *[]) {
"MII" ,
"RR" ,
"RS" ,
"RSI" ,
"RX" ,
"SI" ,
"SMI" ,
"SS" ,
NULL,
},
},
{
.byte = 1 ,
.mask = 0 x0f,
.format = (char *[]) {
"RI" ,
"RIL" ,
"SSF" ,
NULL,
},
},
{
.byte = 1 ,
.mask = 0 xff,
.format = (char *[]) {
"E" ,
"IE" ,
"RRE" ,
"RRF" ,
"RRR" ,
"S" ,
"SIL" ,
"SSE" ,
NULL,
},
},
{
.byte = 5 ,
.mask = 0 xff,
.format = (char *[]) {
"RIE" ,
"RIS" ,
"RRS" ,
"RSE" ,
"RSL" ,
"RSY" ,
"RXE" ,
"RXF" ,
"RXY" ,
"SIY" ,
"VRI" ,
"VRR" ,
"VRS" ,
"VRV" ,
"VRX" ,
"VSI" ,
NULL,
},
},
};
static struct insn_type *insn_format_to_type(char *format)
{
char tmp[STRING_SIZE_MAX];
char *base_format, **ptr;
int i;
strcpy(tmp, format);
base_format = tmp;
base_format = strsep(&base_format, "_" );
for (i = 0 ; i < sizeof (insn_type_table) / sizeof (insn_type_table[0 ]); i++) {
ptr = insn_type_table[i].format;
while (*ptr) {
if (!strcmp(base_format, *ptr))
return &insn_type_table[i];
ptr++;
}
}
exit (EXIT_FAILURE);
}
static void read_instructions(struct gen_opcode *desc)
{
struct insn insn;
int rc, i;
while (1 ) {
rc = scanf("%s %s %s" , insn.opcode, insn.name, insn.format);
if (rc == EOF)
break ;
if (rc != 3 )
exit (EXIT_FAILURE);
insn.type = insn_format_to_type(insn.format);
insn.name_len = strlen(insn.name);
for (i = 0 ; i <= insn.name_len; i++)
insn.upper[i] = toupper((unsigned char )insn.name[i]);
desc->nr++;
desc->insn = realloc(desc->insn, desc->nr * sizeof (*desc->insn));
if (!desc->insn)
exit (EXIT_FAILURE);
desc->insn[desc->nr - 1 ] = insn;
}
}
static int cmpformat(const void *a, const void *b)
{
return strcmp(((struct insn *)a)->format, ((struct insn *)b)->format);
}
static void print_formats(struct gen_opcode *desc)
{
char *format;
int i, count;
qsort(desc->insn, desc->nr, sizeof (*desc->insn), cmpformat);
format = "" ;
count = 0 ;
printf("enum {\n" );
for (i = 0 ; i < desc->nr; i++) {
if (!strcmp(format, desc->insn[i].format))
continue ;
count++;
format = desc->insn[i].format;
printf("\tINSTR_%s,\n" , format);
}
printf("}; /* %d */\n\n", count);
}
static int cmp_long_insn(const void *a, const void *b)
{
return strcmp(((struct insn *)a)->name, ((struct insn *)b)->name);
}
static void print_insn_name(const char *name)
{
size_t i, len;
len = strlen(name);
printf("{" );
for (i = 0 ; i < len; i++)
printf(" \'%c\'," , name[i]);
printf(" }" );
}
static void print_long_insn(struct gen_opcode *desc)
{
struct insn *insn;
int i, count;
qsort(desc->insn, desc->nr, sizeof (*desc->insn), cmp_long_insn);
count = 0 ;
printf("enum {\n" );
for (i = 0 ; i < desc->nr; i++) {
insn = &desc->insn[i];
if (insn->name_len < 6 )
continue ;
printf("\tLONG_INSN_%s,\n" , insn->upper);
count++;
}
printf("}; /* %d */\n\n", count);
printf("#define LONG_INSN_INITIALIZER { \\\n" );
for (i = 0 ; i < desc->nr; i++) {
insn = &desc->insn[i];
if (insn->name_len < 6 )
continue ;
printf("\t[LONG_INSN_%s] = " , insn->upper);
print_insn_name(insn->name);
printf(", \\\n" );
}
printf("}\n\n" );
}
static void print_opcode(struct insn *insn, int nr)
{
char *opcode;
opcode = insn->opcode;
if (insn->type->byte != 0 )
opcode += 2 ;
printf("\t[%4d] = { .opfrag = 0x%s, .format = INSTR_%s, " , nr, opcode, insn->format);
if (insn->name_len < 6 ) {
printf(".name = " );
print_insn_name(insn->name);
} else {
printf(".offset = LONG_INSN_%s" , insn->upper);
}
printf(" }, \\\n" );
}
static void add_to_group(struct gen_opcode *desc, struct insn *insn, int offset)
{
struct insn_group *group;
group = desc->group ? &desc->group[desc->nr_groups - 1 ] : NULL;
if (group && (!strncmp(group->opcode, insn->opcode, 2 ) || group->type->byte == 0 )) {
group->count++;
return ;
}
desc->nr_groups++;
desc->group = realloc(desc->group, desc->nr_groups * sizeof (*desc->group));
if (!desc->group)
exit (EXIT_FAILURE);
group = &desc->group[desc->nr_groups - 1 ];
memcpy(group->opcode, insn->opcode, 2 );
group->type = insn->type;
group->offset = offset;
group->count = 1 ;
}
static int cmpopcode(const void *a, const void *b)
{
return strcmp(((struct insn *)a)->opcode, ((struct insn *)b)->opcode);
}
static void print_opcode_table(struct gen_opcode *desc)
{
char opcode[2 ] = "" ;
struct insn *insn;
int i, offset;
qsort(desc->insn, desc->nr, sizeof (*desc->insn), cmpopcode);
printf("#define OPCODE_TABLE_INITIALIZER { \\\n" );
offset = 0 ;
for (i = 0 ; i < desc->nr; i++) {
insn = &desc->insn[i];
if (insn->type->byte == 0 )
continue ;
add_to_group(desc, insn, offset);
if (strncmp(opcode, insn->opcode, 2 )) {
memcpy(opcode, insn->opcode, 2 );
printf("\t/* %.2s */ \\\n", opcode);
}
print_opcode(insn, offset);
offset++;
}
printf("\t/* 1-byte opcode instructions */ \\\n");
for (i = 0 ; i < desc->nr; i++) {
insn = &desc->insn[i];
if (insn->type->byte != 0 )
continue ;
add_to_group(desc, insn, offset);
print_opcode(insn, offset);
offset++;
}
printf("}\n\n" );
}
static void print_opcode_table_offsets(struct gen_opcode *desc)
{
struct insn_group *group;
int i;
printf("#define OPCODE_OFFSET_INITIALIZER { \\\n" );
for (i = 0 ; i < desc->nr_groups; i++) {
group = &desc->group[i];
printf("\t{ .opcode = 0x%.2s, .mask = 0x%02x, .byte = %d, .offset = %d, .count = %d }, \\\n" ,
group->opcode, group->type->mask, group->type->byte, group->offset, group->count);
}
printf("}\n\n" );
}
int main(int argc, char **argv)
{
struct gen_opcode _desc = { 0 };
struct gen_opcode *desc = &_desc;
read_instructions(desc);
printf("#ifndef __S390_GENERATED_DIS_DEFS_H__\n" );
printf("#define __S390_GENERATED_DIS_DEFS_H__\n" );
printf("/*\n");
printf(" * DO NOT MODIFY.\n" );
printf(" *\n" );
printf(" * This file was generated by %s\n" , __FILE__);
printf(" */\n\n" );
print_formats(desc);
print_long_insn(desc);
print_opcode_table(desc);
print_opcode_table_offsets(desc);
printf("#endif\n" );
exit (EXIT_SUCCESS);
}
Messung V0.5 in Prozent C=98 H=87 G=92
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland