Skip to content

Instantly share code, notes, and snippets.

@kusabanachi
Last active Oct 11, 2015
Embed
What would you like to do?
Disassembler for VAX binary.
package mypackage;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.PushbackInputStream;
import java.util.*;
import static mypackage.OperandType.*;
public class VaxDisasm {
public static void main(String[] args) {
SourceStream source = null;
try {
source = new SourceStream(args[0]);
do {
Instruction ins = Instruction.fetchFrom(source);
if (ins == null) {
break;
}
System.out.println(ins.mnemonic());
} while (true);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (source != null) {
source.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class SourceStream {
private PushbackInputStream istream;
private int count;
SourceStream(String srcFileName) throws IOException {
istream = new PushbackInputStream(new FileInputStream(srcFileName), 2);
count = 0;
}
public void close() throws IOException {
istream.close();
}
public int pc() {
return count;
}
public int read() throws IOException {
int val = istream.read();
if (val != -1) {
++count;
}
return val;
}
public void unread(int val) throws IOException {
istream.unread(val);
--count;
}
public int lookAhead() throws IOException {
int val = istream.read();
istream.unread(val);
return val;
}
}
class Instruction {
private final Opcode opcode;
private final List<Operand> operands;
protected Instruction(Opcode opc, List<Operand> oprs) {
this.opcode = opc;
this.operands = oprs;
}
public String mnemonic() {
int nOpr = operands.size();
StringBuilder sb = new StringBuilder(opcode.mnemonic());
if (nOpr > 0) {
sb.append(" ");
sb.append(operands.get(0).mnemonic());
}
for (int i = 1; i < nOpr; i++) {
sb.append(",");
sb.append(operands.get(i).mnemonic());
}
return sb.toString();
}
public static Instruction fetchFrom(SourceStream source) throws IOException {
Opcode opc = Opcode.fetchFrom(source);
if (opc == null) {
return NotOpcode.fetchFrom(source);
}
ArrayList<Operand> oprs = new ArrayList<Operand>(opc.operands.length);
for (OperandType type : opc.operands) {
Operand opr = Operand.fetchFrom(source, type);
if (opr == null) {
return null;
}
oprs.add(opr);
}
return new Instruction(opc, oprs);
}
}
class NotOpcode extends Instruction {
private short val;
protected NotOpcode(short val) {
super(null, null);
this.val = val;
}
@Override
public String mnemonic() {
return String.format(".word 0x%x", val);
}
public static NotOpcode fetchFrom(SourceStream source) throws IOException {
int first, second;
if ((first = source.read()) == -1) {
return null;
}
if ((second = source.read()) == -1) {
return null;
}
return new NotOpcode((short)((first << 8) + second));
}
}
enum OperandType {
B(1), W(2), L(4), Q(8), O(16),
F(4, " [f-float]"), D(8, " [d-float]"), G(8, " [g-float]"), H(16, " [h-float]"),
BrB(1), BrW(2);
public final int size;
public final String annotation;
private OperandType(int sz) {
this.size = sz;
this.annotation = "";
}
private OperandType(int sz, String ann) {
this.size = sz;
this.annotation = ann;
}
}
enum Opcode {
HALT (0x0), NOP (0x1), REI (0x2), BPT (0x3),
RET (0x4), RSB (0x5), LDPCTX(0x6), SVPCTX(0x7),
CVTPS (0x8, W,B,W,B), CVTSP (0x9,W,B,W,B),
INDEX (0xa, L,L,L,L,L,L), CRC (0xb, B,L,W,B),
PROBER(0xc, B,W,B), PROBEW(0xd, B,W,B), INSQUE(0xe, B,B), REMQUE(0xf, B,W),
BSBB (0x10, BrB), BRB (0x11, BrB), BNEQ (0x12, BrB), BEQL (0x13, BrB),
BGTR (0x14, BrB), BLEQ (0x15, BrB), JSB (0x16, B), JMP (0x17, B),
BGEQ (0x18, BrB), BLSS (0x19, BrB), BGTRU (0x1a, BrB), BLEQU (0x1b, BrB),
BVC (0x1c, BrB), BVS (0x1d, BrB), BCC (0x1e, BrB), BLSSU (0x1f, BrB),
ADDP4 (0x20, W,B,W,B), ADDP6 (0x21, W,B,W,B,W,B), SUBP4 (0x22, W,B,W,B), SUBP6 (0x23, W,B,W,B,W,B),
CVTPT (0x24, W,B,B,W,B), MULP (0x25, W,B,W,B,W,B), CVTTP (0x26, W,B,B,W,B), DIVP (0x27, W,B,W,B,W,B),
MOVC3 (0x28, W,B,B), CMPC3 (0x29, W,B,B), SCANC (0x2a, W,B,B,B), SPANC (0x2b, W,B,B,B),
MOVC5 (0x2c, W,B,B,W,B), CMPC5 (0x2d, W,B,B,W,B), MOVTC (0x2e, W,B,B,B,W,B), MOVTUC(0x2f, W,B,B,B,W,B),
BSBW (0x30, BrW), BRW (0x31, BrW), CVTWL (0x32, W,L), CVTDH (0x32fd, D,H),
CVTWB (0x33, W,B), CVTGF (0x33fd, G,F), MOVP (0x34, W,B,B), CMPP3 (0x35, W,B,B),
CVTPL (0x36, W,B,L), CMPP4 (0x37, W,B,W,B), EDITPC(0x38, W,B,B,B), MATCHC(0x39, W,B,W,B),
LOCC (0x3a, B,W,B), SKPC (0x3b, B,W,B), MOVZWL(0x3c, W,L), ACBW (0x3d, W,W,W,BrW),
MOVAW (0x3e, W,L), PUSHAW(0x3f, W),
ADDF2 (0x40, F,F), ADDG2 (0x40fd, G,G), ADDF3 (0x41, F,F,F), ADDG3 (0x41fd, G,G,G),
SUBF2 (0x42, F,F), SUBG2 (0x42fd, G,G), SUBF3 (0x43, F,F,F), SUBG3 (0x43fd, G,G,G),
MULF2 (0x44, F,F), MULG2 (0x44fd, G,G), MULF3 (0x45, F,F,F), MULG3 (0x45fd, G,G,G),
DIVF2 (0x46, F,F), DIVG2 (0x46fd, G,G), DIVF3 (0x47, F,F,F), DIVG3 (0x47fd, G,G,G),
CVTFB (0x48, F,B), CVTGB (0x48fd, G,B), CVTFW (0x49, F,W), CVTGW (0x49fd, G,W),
CVTFL (0x4a, F,L), CVTGL (0x4afd, G,L), CVTRFL(0x4b, F,L), CVTRGL(0x4bfd, G,L),
CVTBF (0x4c, B,F), CVTBG (0x4cfd, B,G), CVTWF (0x4d, W,F), CVTWG (0x4dfd, W,G),
CVTLF (0x4e, L,F), CVTLG (0x4efd, L,G), ACBF (0x4f, F,F,F,BrW), ACBG (0x4ffd, G,G,G,BrW),
MOVF (0x50, F,F), MOVG (0x50fd, G,G), CMPF (0x51, F,F), CMPG (0x51fd, G,G),
MNEGF (0x52, F,F), MNEGG (0x52fd, G,G), TSTF (0x53, F), TSTG (0x53fd, G),
EMODF (0x54, F,B,F,L,F), EMODG (0x54fd, G,W,G,L,G), POLYF (0x55, F,W,B), POLYG (0x55fd, G,W,B),
CVTFD (0x56, F,D), CVTGH (0x56fd, G,H), ADAWI (0x58, W,W),
INSQHI(0x5c, B,Q), INSQTI(0x5d, B,Q), REMQHI(0x5e, Q,L), REMQTI(0x5f, Q,L),
ADDD2 (0x60, D,D), ADDH2 (0x60fd, H,H), ADDD3 (0x61, D,D,D), ADDH3 (0x61fd, H,H,H),
SUBD2 (0x62, D,D), SUBH2 (0x62fd, H,H), SUBD3 (0x63, D,D,D), SUBH3 (0x63fd, H,H,H),
MULD2 (0x64, D,D), MULH2 (0x64fd, H,H), MULD3 (0x65, D,D,D), MULH3 (0x65fd, H,H,H),
DIVD2 (0x66, D,D), DIVH2 (0x66fd, H,H), DIVD3 (0x67, D,D,D), DIVH3 (0x67fd, H,H,H),
CVTDB (0x68, D,B), CVTHB (0x68fd, H,B), CVTDW (0x69, D,W), CVTHW (0x69fd, H,W),
CVTDL (0x6a, D,L), CVTHL (0x6afd, H,L), CVTRDL(0x6b, D,L), CVTRHL(0x6bfd, H,L),
CVTBD (0x6c, B,D), CVTBH (0x6cfd, B,H), CVTWD (0x6d, W,D), CVTWH (0x6dfd, W,H),
CVTLD (0x6e, L,D), CVTLH (0x6efd, L,H), ACBD (0x6f, D,D,D,BrW), ACBH (0x6ffd, H,H,H,BrW),
MOVD (0x70, D,D), MOVH (0x70fd, H,H), CMPD (0x71, D,D), CMPH (0x71fd, H,H),
MNEGD (0x72, D,D), MNEGH (0x72fd, H,H), TSTD (0x73, D), TSTH (0x73fd, H),
EMODD (0x74, D,B,D,L,D), EMODH (0x74fd, H,W,H,L,H),
POLYD (0x75, D,W,B), POLYH (0x75fd, H,W,B), CVTDF (0x76, D,F), CVTHG (0x76fd, H,G),
ASHL (0x78, B,L,L), ASHQ (0x79, B,Q,Q), EMUL (0x7a, L,L,L,Q), EDIV (0x7b, L,Q,L,L),
CLRQ (0x7c, Q), CLRO (0x7cfd, O), // CLRD (0x7c, D), CLRG (0x7c, G), CLRH (0x7cfd, H),
MOVQ (0x7d, Q,Q), MOVO (0x7dfd, O,O),
MOVAQ (0x7e, Q,L), MOVAO (0x7efd, O,L), // MOVAD(0x7e, D,L), MOVAG(0x7e, G,L), MOVAH(0x7efd, H,L),
PUSHAQ(0x7f, Q), PUSHAO(0x7ffd, O), // PUSHAD(0x7f, D), PUSHAG(0x7f, G), PUSHAH(0x7ffd, H),
ADDB2 (0x80, B,B), ADDB3 (0x81, B,B,B), SUBB2 (0x82, B,B), SUBB3 (0x83, B,B,B),
MULB2 (0x84, B,B), MULB3 (0x85, B,B,B), DIVB2 (0x86, B,B), DIVB3 (0x87, B,B,B),
BISB2 (0x88, B,B), BISB3 (0x89, B,B,B), BICB2 (0x8a, B,B), BICB3 (0x8b, B,B,B),
XORB2 (0x8c, B,B), XORB3 (0x8d, B,B,B), MNEGB (0x8e, B,B), CASEB (0x8f, B,B,B),
MOVB (0x90, B,B), CMPB (0x91, B,B), MCOMB (0x92, B,B), BITB (0x93, B,B),
CLRB (0x94, B), TSTB (0x95, B), INCB (0x96, B), DECB (0x97, B),
CVTBL (0x98, B,L), CVTFH (0x98fd, F,H), CVTBW (0x99, B,W), CVTFG (0x99fd, F,G),
MOVZBL(0x9a, B,L), MOVZBW(0x9b, B,W), ROTL (0x9c, B,L,L), ACBB (0x9d, B,B,B,BrW),
MOVAB (0x9e, B,L), PUSHAB(0x9f, B),
ADDW2 (0xa0, W,W), ADDW3 (0xa1, W,W,W), SUBW2 (0xa2, W,W), SUBW3 (0xa3, W,W,W),
MULW2 (0xa4, W,W), MULW3 (0xa5, W,W,W), DIVW2 (0xa6, W,W), DIVW3 (0xa7, W,W,W),
BISW2 (0xa8, W,W), BISW3 (0xa9, W,W,W), BICW2 (0xaa, W,W), BICW3 (0xab, W,W,W),
XORW2 (0xac, W,W), XORW3 (0xad, W,W,W), MNEGW (0xae, W,W), CASEW (0xaf, W,W,W),
MOVW (0xb0, W,W), CMPW (0xb1, W,W), MCOMW (0xb2, W,W), BITW (0xb3, W,W),
CLRW (0xb4, W), TSTW (0xb5, W), INCW (0xb6, W), DECW (0xb7, W),
BISPSW(0xb8, W), BICPSW(0xb9, W), POPR (0xba, W), PUSHR (0xbb, W),
CHMK (0xbc, W), CHME (0xbd, W), CHMS (0xbe, W), CHMU (0xbf, W),
ADDL2 (0xc0, L,L), ADDL3 (0xc1, L,L,L), SUBL2 (0xc2, L,L), SUBL3 (0xc3, L,L,L),
MULL2 (0xc4, L,L), MULL3 (0xc5, L,L,L), DIVL2 (0xc6, L,L), DIVL3 (0xc7, L,L,L),
BISL2 (0xc8, L,L), BISL3 (0xc9, L,L,L), BICL2 (0xca, L,L), BICL3 (0xcb, L,L,L),
XORL2 (0xcc, L,L), XORL3 (0xcd, L,L,L), MNEGL (0xce, L,L), CASEL (0xcf, L,L,L),
MOVL (0xd0, L,L), CMPL (0xd1, L,L), MCOML (0xd2, L,L), BITL (0xd3, L,L),
CLRF (0xd4, F), // CLRL (0xd4, L),
TSTL (0xd5, L), INCL (0xd6, L), DECL (0xd7, L),
ADWC (0xd8, L,L), SBWC (0xd9, L,L), MTPR (0xda, L,L), MFPR (0xdb, L,L),
MOVPSL(0xdc, L), PUSHL (0xdd, L), MOVAL (0xde, L,L), // MOVAF (0xde, F,L)
PUSHAL(0xdf, L), // PUSHAF(0xdf, F)
BBS (0xe0, L,B,BrB), BBC (0xe1, L,B,BrB), BBSS (0xe2, L,B,BrB), BBCS (0xe3, L,B,BrB),
BBSC (0xe4, L,B,BrB), BBCC (0xe5, L,B,BrB), BBSSI (0xe6, L,B,BrB), BBCCI (0xe7, L,B,BrB),
BLBS (0xe8, L,BrB), BLBC (0xe9, L,BrB), FFS (0xea, L,B,B,L), FFC (0xeb, L,B,B,L),
CMPV (0xec, L,B,B,L), CMPZV (0xed, L,B,B,L), EXTV (0xee, L,B,B,L), EXTZV (0xef, L,B,B,L),
INSV (0xf0, L,L,B,B), ACBL (0xf1, L,L,L,BrW), AOBLSS(0xf2, L,L,BrB), AOBLEQ(0xf3, L,L,BrB),
SOBGEQ(0xf4, L,BrB), SOBGTR(0xf5, L,BrB), CVTLB (0xf6, L,B), CVTHF (0xf6fd, H,F),
CVTLW (0xf7, L,W), CVTHD (0xf7fd, H,D), ASHP (0xf8, B,W,B,B,W,B), CVTLP (0xf9, L,W,B),
CALLG (0xfa, B,B), CALLS (0xfb, L,B), XFC (0xfc),
BUGL (0xfdff, L), BUGW (0xfeff, W);
private final int code;
public final OperandType[] operands;
private Opcode(int code, OperandType... oprs) {
this.code = code;
this.operands = oprs;
}
public String mnemonic() {
return name().toLowerCase();
}
private final static HashMap<Integer, Opcode> opCodeMap;
static {
opCodeMap = new HashMap<Integer, Opcode>(Opcode.values().length);
for (Opcode opc : Opcode.values()) {
opCodeMap.put(opc.code, opc);
}
}
public static Opcode fetchFrom(SourceStream source) throws IOException {
int[] vals = new int[2];
int code = 0;
for (int i = 0; i < 2; i++) {
vals[i] = source.read();
if (vals[i] == -1) {
return null;
}
code += vals[i] << i * 8;
Opcode opc = opCodeMap.get(code);
if (opc != null) {
return opc;
}
}
source.unread(vals[1]);
source.unread(vals[0]);
return null;
}
}
class Operand {
private static final int PC = 0xf;
protected String mnemonic;
public String mnemonic() {
return mnemonic;
}
public static Operand fetchFrom(SourceStream source, OperandType type) throws IOException {
if (type != OperandType.BrB && type != OperandType.BrW) {
return fetchGeneralAddress(source, type);
} else {
return fetchBranchAddress(source, type);
}
}
public static Operand fetchGeneralAddress(SourceStream source, OperandType type) throws IOException {
int head = source.lookAhead();
if (head == -1) {
return null;
}
Operand opr = new Operand();
switch (head >>> 4) {
case 0x0: case 0x1: case 0x2: case 0x3:
opr.fetchLiteral(source, type);
break;
case 0x4:
opr.fetchIndex(source, type);
break;
case 0x5:
opr.fetchRegister(source);
break;
case 0x6:
opr.fetchRegisterDeferred(source);
break;
case 0x7:
opr.fetchAutoDecrement(source);
break;
case 0x8:
opr.fetchAutoIncrement(source, type);
break;
case 0x9:
opr.fetchAutoIncrementDeferred(source);
break;
case 0xA: case 0xC: case 0xE:
opr.fetchDisplacement(source);
break;
case 0xB: case 0xD: case 0xF:
opr.fetchDisplacementDeferred(source);
break;
}
return opr;
}
public static Operand fetchBranchAddress(SourceStream source, OperandType type) throws IOException {
int offset = 0;
for (int i = 0; i < type.size; i++) {
offset = (offset >>> 8) + (source.read() << 24);
}
offset >>= (4 - type.size) * 8; // sign extension
int address = source.pc() + offset;
Operand opr = new Operand();
opr.mnemonic = String.format("0x%x", address);
return opr;
}
private void fetchLiteral(SourceStream source, OperandType type) throws IOException {
int val = source.read();
mnemonic = String.format("$0x%x", val & 0x3f) + type.annotation;
}
private void fetchIndex(SourceStream source, OperandType type) throws IOException {
int index = source.read();
Operand base = fetchGeneralAddress(source, type);
mnemonic = base.mnemonic() + "[" + regStr(index) + "]";
}
private void fetchRegister(SourceStream source) throws IOException {
int val = source.read();
mnemonic = regStr(val);
}
private void fetchRegisterDeferred(SourceStream source) throws IOException {
int val = source.read();
mnemonic = "(" + regStr(val) + ")";
}
private void fetchAutoDecrement(SourceStream source) throws IOException {
int val = source.read();
mnemonic = "-(" + regStr(val) + ")";
}
private void fetchAutoIncrement(SourceStream source, OperandType type) throws IOException {
int val = source.read();
if (isPC(val)) {
int[] byteArray = new int[type.size];
for (int i = 0; i < type.size; i++) {
byteArray[i] = source.read();
}
StringBuilder sb = new StringBuilder("$0x");
for (int i = type.size - 1; i >= 0; i--) {
sb.append(String.format("%02x", byteArray[i]));
}
mnemonic = sb.append(type.annotation).toString();
} else {
mnemonic = "(" + regStr(val) + ")+";
}
}
private void fetchAutoIncrementDeferred(SourceStream source) throws IOException {
int val = source.read();
if (isPC(val)) {
int absVal = 0;
for (int i = 0; i < 4; i++) {
absVal += source.read() << i * 8;
}
mnemonic = String.format("*0x%x", absVal);
} else {
mnemonic = "@(" + regStr(val) + ")+";
}
}
private void fetchDisplacement(SourceStream source) throws IOException {
int head = source.read();
int size = (int)Math.pow(2, (head >>> 5) - 5); // 1, 2, 4 bytes
int dispVal = 0;
for (int i = 0; i < size; i++) {
dispVal = (dispVal >>> 8) + (source.read() << 24);
}
dispVal >>= (4 - size) * 8; // sign extension
if (isPC(head)) {
mnemonic = String.format("0x%x", source.pc() + dispVal);
} else {
mnemonic = String.format("0x%x(", dispVal) + regStr(head) + ")";
}
}
private void fetchDisplacementDeferred(SourceStream source) throws IOException {
fetchDisplacement(source);
mnemonic = "*" + mnemonic;
}
private String regStr(int val) {
final String [] regs = {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc"};
return regs[val & 0xf];
}
private boolean isPC(int val) {
return (val & 0xf) == PC;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment