/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
*/
/*
* Copyright 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
*/
#include <stdio.h>
#include <libdisasm.h>
#include <sys/sysmacros.h>
#include <sys/byteorder.h>
#include "libdisasm_impl.h"
/*
* Throughout this file, the instruction format names based on:
* SA22-7832-09 z/Architecture Principles of Operation
*
* System/370, ESA/390, and earlier z/Architecture POP use slightly
* different names for the formats (the variant names are numeric). For the
* sake of simplicity, we use the most detailed definitions - z/Architecture.
*
* For ESA/390 we map the formats:
* E -> E
* I -> I
* RR -> RR
* RRE -> RRE
* RRF -> RRD & RRFa-e
* RX -> RXa-b
* RXE -> RXE
* RXF -> RXF
* RS -> RSa-b
* RSE -> RSYa-b
* RSL -> RSLa
* RSI -> RSI
* RI -> RIa-c
* RIL -> RILa-c
* SI -> SI
* S -> S
* SS -> SSa-b & SSd-e
* SSE -> SSE
*
* For System/370 we map the formats:
* RR -> RR
* RX -> RXa-b
* RS -> RSa-b
* SI -> SI
* S -> S
* SS -> SSa-c
*
* Disassembly begins in tbl_xx. The first byte of the instruction is used
* as the index. This yields either an instruction or a sub-table.
*
* If an instruction is encountered, its format field is used to format the
* instruction.
*
* There are two types of sub-tables: extended opcode tables (indicated with
* IF_TBL) or a multiple mnemonics tables (indicated with IF_MULTI).
*
* Extended opcode tables indicade which additional bits of the instruction
* should be inspected. These bits are used as an index into the sub table.
*
* Multiple mnemonic tables are used to print different mnemonics depending
* on the architecture. Over the years, certain instructions got a new
* preferred mnemonic. For example, 0xa70 is test-under-mask-high (tmh) on
* System/390. On z/Architecture systems, the instruction behaves
* identically (and the assembler hapilly accepts tmh), but the preferred
* mnemonic is tmlh (test-under-mask-low-high) because z/Architecture
* extended the general purpose registers from 32 bits to 64 bits. The
* current architecture flag (e.g., F_390) is used to index into the
* sub-table.
*
* Regardless of which sub-table is encountered, the selected entry in the
* sub-table is interpreted using the same rules as the contents of tbl_xx.
*
* Finally, we use the extended opcode sub-table mechanism to pretty print
* the branching instructions. All branches are conditional based on a
* 4-bit mask indicating which value of the condition code will result in a
* taken branch. In order to produce a more human friendly output, we use
* the 4-bit mask as an extended opcode to break up the branching
* instruction into 16 different ones. For example, instead of printing:
*
* bc 7,0x123(%r1,%r2)
*
* we print:
*
* bne 0x123(%r1,%r2)
*
* macros and therefore the below tables can be sparse. We rely on unset
* entries having zero format fields (aka. IF_INVAL) per C99.
*/
/* BEGIN CSTYLED */
enum ifmt {
/* invalid */
IF_INVAL = 0,
/* indirection */
/* 2-byte */
/* 4-byte */
/* 6-byte */
};
/* END CSTYLED */
struct inst_table {
union {
struct {
const char *it_name;
unsigned it_flags;
} it_inst;
struct {
} it_table;
struct {
} it_multi;
} it_u;
};
union inst {
struct {
} diag;
struct {
uint8_t i;
} i;
struct {
} ie;
struct {
} mii;
struct {
} rr;
struct {
} rrd;
struct {
} rre;
struct {
} rrf_ab;
struct {
} rrf_cde;
struct {
} rrs;
struct {
} rx_a;
struct {
} rx_b;
struct {
} rxe;
struct {
} rxf;
struct {
} rxy_a;
struct {
} rxy_b;
struct {
} rs_a;
struct {
} rs_b;
struct {
} rsl_a;
struct {
} rsl_b;
struct {
} rsi;
struct {
} rsy_a;
struct {
} rsy_b;
struct {
} ri_a;
struct {
} ri_b;
struct {
} ri_c;
struct {
} rie_a;
struct {
} rie_b;
struct {
} rie_c;
struct {
} rie_d;
struct {
} rie_e;
struct {
} rie_f;
struct {
} ril_a;
struct {
} ril_b;
struct {
} ril_c;
struct {
} ris;
struct {
} si;
struct {
} sil;
struct {
} siy;
struct {
} smi;
struct {
} s;
struct {
uint8_t l;
} ss_a;
struct {
} ss_b;
struct {
} ss_c;
struct {
} ss_d;
struct {
} ss_e;
struct {
} ss_f;
struct {
} sse;
struct {
} ssf;
};
.it_name = (m), \
}, \
}
.it_off = (o), \
.it_shift = (s), \
.it_mask = (m), \
}, \
}
}
/*
* Instruction tables based on:
* GA22-7000-4 System/370 Principles of Operation
* SA22-7201-08 ESA/390 Principles of Operation
* SA22-7832-09 z/Architecture Principles of Operation
*/
/* BEGIN CSTYLED */
};
};
};
/* the preferred mnemonic changed over time */
};
/* the preferred mnemonic changed over time */
};
/* the preferred mnemonic changed over time */
};
/* the preferred mnemonic changed over time */
};
/* the meaning of this instruction changed over time */
};
/* the meaning of this instruction changed over time */
};
};
/* the preferred mnemonic changed over time */
};
/* the preferred mnemonic changed over time */
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
};
/* END CSTYLED */
/* how masks are printed */
static const char *M[16] = {
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "11", "12", "13", "14", "15",
};
/* how general purpose regs are printed */
static const char *R[16] = {
"%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
"%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
};
/* how control regs are printed */
static const char *C[16] = {
"%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7",
"%c8", "%c9", "%c10", "%c11", "%c12", "%c13", "%c14", "%c15",
};
/* B and X registers are still registers - print them the same way */
#define B R
#define X R
static inline uint32_t
{
}
static inline uint32_t
{
}
static inline int32_t
{
}
static inline uint32_t
{
}
static inline int32_t
{
/* sign extend */
if (tmp & 0x00800000)
return (0xff000000 | tmp);
return (tmp);
}
static inline uint32_t
{
}
static inline int32_t
{
/* sign extend */
if (tmp & 0x800)
return (0xfffff000 | tmp);
return (tmp);
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
/* nothing to do */
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
if (flags & F_SIGNED_IMM)
else
i2);
}
/* ARGSUSED */
static void
{
}
static void
{
if (flags & F_HIDE_MASK)
else
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
/* a branch uses r1 as a mask */
if (flags & F_HIDE_MASK)
else if (flags & F_R1_IS_MASK)
else
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
if (flags & F_HIDE_MASK)
else
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
} else {
}
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
} else {
}
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
/* ARGSUSED */
static void
{
}
int) = {
};
/*
* Even if we don't know how to disassemble the instruction, we know how long
* it is, so we always succeed. That is why we can get away with returning
* void.
*/
static void
{
int tmp;
/* nothing to do */
if (buflen == 0)
return;
int idx;
}
}
goto inval;
goto inval;
if (tmp < 0)
return;
return;
}
static int
{
archflags == DIS_S390_64)
return (1);
return (0);
}
static int
{
int mach;
int len;
return (-1);
if (len > 0 &&
return (-1);
case DIS_S370:
break;
case DIS_S390_31:
break;
case DIS_S390_64:
break;
}
return (0);
}
/* ARGSUSED */
static int
{
return (2);
}
/* ARGSUSED */
static int
{
return (6);
}
};