diff --git a/Jocaml.java b/Jocaml.java index bbc6db7..ef219c4 100644 --- a/Jocaml.java +++ b/Jocaml.java @@ -1,18 +1,177 @@ import java.io.File; import java.io.FileInputStream; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.channels.Channels; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class Jocaml { private static String TRAILER_MAGIC = "Caml1999X028"; private static long MARSHAL_MAGIC_SMALL = 0x8495A6BE; private static long MARSHAL_MAGIC_BIG = 0x8495A6BF; + private static enum CamlInst { + ACC0(0, 0), + ACC1(1, 0), + ACC2(2, 0), + ACC3(3, 0), + ACC4(4, 0), + ACC5(5, 0), + ACC6(6, 0), + ACC7(7, 0), + ACC(8, 1), + PUSH(9, 0), + PUSHACC0(10, 0), + PUSHACC1(11, 0), + PUSHACC2(12, 0), + PUSHACC3(13, 0), + PUSHACC4(14, 0), + PUSHACC5(15, 0), + PUSHACC6(16, 0), + PUSHACC7(17, 0), + PUSHACC(18, 1), + POP(19, 1), + ASSIGN(20, 1), + ENVACC1(21, 0), + ENVACC2(22, 0), + ENVACC3(23, 0), + ENVACC4(24, 0), + ENVACC(25, 1), + PUSHENVACC1(26, 0), + PUSHENVACC2(27, 0), + PUSHENVACC3(28, 0), + PUSHENVACC4(29, 0), + PUSHENVACC(30, 1), + PUSH_RETADDR(31, 1), + APPLY(32, 1), + APPLY1(33, 0), + APPLY2(34, 0), + APPLY3(35, 0), + APPTERM(36, 2), + APPTERM1(37, 1), + APPTERM2(38, 1), + APPTERM3(39, 1), + RETURN(40, 1), + RESTART(41, 0), + GRAB(42, 1), + CLOSURE(43, 2), + CLOSUREREC(44, 4), + OFFSETCLOSUREM2(45, 0), + OFFSETCLOSURE0(46, 0), + OFFSETCLOSURE2(47, 0), + OFFSETCLOSURE(48, 1), + PUSHOFFSETCLOSUREM2(49, 0), + PUSHOFFSETCLOSURE0(50, 0), + PUSHOFFSETCLOSURE2(51, 0), + PUSHOFFSETCLOSURE(52, 1), + GETGLOBAL(53, 1), + PUSHGETGLOBAL(54, 1), + GETGLOBALFIELD(55, 2), + PUSHGETGLOBALFIELD(56, 2), + SETGLOBAL(57, 1), + ATOM0(58, 0), + ATOM(59, 1), + PUSHATOM0(60, 0), + PUSHATOM(61, 1), + MAKEBLOCK(62, 2), + MAKEBLOCK1(63, 1), + MAKEBLOCK2(64, 1), + MAKEBLOCK3(65, 1), + MAKEFLOATBLOCK(66, 1), + GETFIELD0(67, 0), + GETFIELD1(68, 0), + GETFIELD2(69, 0), + GETFIELD3(70, 0), + GETFIELD(71, 1), + GETFLOATFIELD(72, 1), + SETFIELD0(73, 0), + SETFIELD1(74, 0), + SETFIELD2(75, 0), + SETFIELD3(76, 0), + SETFIELD(77, 1), + SETFLOATFIELD(78, 1), + VECTLENGTH(79, 0), + GETVECTITEM(80, 0), + SETVECTITEM(81, 0), + GETBYTESCHAR(82, 0), + SETBYTESCHAR(83, 0), + BRANCH(84, 1), + BRANCHIF(85, 1), + BRANCHIFNOT(86, 1), + SWITCH(87, 2), + BOOTNOT(88, 0), + PUSHTRAP(89, 1), + POPTRAP(90, 0), + RAISE(91, 0), + CHECK_SIGNALS(92, 0), + C_CALL1(93, 1), + C_CALL2(94, 1), + C_CALL3(95, 1), + C_CALL4(96, 1), + C_CALL5(97, 1), + C_CALLN(98, 2), + CONST0(99, 0), + CONST1(100, 0), + CONST2(101, 0), + CONST3(102, 0), + CONSTINT(103, 1), + PUSHCONST0(104, 0), + PUSHCONST1(105, 0), + PUSHCONST2(106, 0), + PUSHCONST3(107, 0), + PUSHCONSTINT(108, 1), + NEGINT(109, 0), + ADDINT(110, 0), + SUBINT(111, 0), + MULINT(112, 0), + DIVINT(113, 0), + MODINT(114, 0), + ANDINT(115, 0), + ORINT(116, 0), + XORINT(117, 0), + LSLINT(118, 0), + LSRINT(119, 0), + ASRINT(120, 0), + EQ(121, 0), + NEQ(122, 0), + LTINT(123, 0), + LEINT(124, 0), + GTINT(125, 0), + GEINT(126, 0), + OFFSETINT(127, 1), + OFFSETREF(128, 1), + ISINT(129, 0), + GETMETHOD(130, 0), + BEQ(131, 2), + BNEQ(132, 2), + BLTINT(133, 2), + BLEINT(134, 2), + BGTINT(135, 2), + BGEINT(136, 2), + ULTINT(137, 0), + UGEINT(138, 0), + BULTINT(139, 2), + BUGEINT(140, 2), + GETPUBMET(141, 2), + GETDYNMET(142, 0), + STOP(143, 0), + EVENT(144, 0), + BREAK(145, 0), + + RERAISE(146, 0), // ??? + RAISE_NOTRACE(147, 0), + GETSTRINGCHAR(148, 0); + + public final int code; + public final int numArgs; + CamlInst(int code, int numArgs) { + this.code = code; + this.numArgs = numArgs; + } + } + private static class CodeOffset { public final int offset; @@ -98,15 +257,15 @@ public class Jocaml { // shared elements case 0x04: { long offset = this.data.get() & (long) 0xff; - return shared.get((int) offset); + return shared.get(shared.size() - 1 - (int) offset); } case 0x05: { long offset = this.data.getShort() & (long) 0xff; - return shared.get((int) offset); + return shared.get(shared.size() - 1 - (int) offset); } case 0x06: { long offset = this.data.getInt() & (long) 0xff; - return shared.get((int) offset); + return shared.get(shared.size() - 1 - (int) offset); } // blocks @@ -223,6 +382,7 @@ public class Jocaml { } public void unmarshal() throws Exception { + this.data.order(ByteOrder.BIG_ENDIAN); int magic = this.data.getInt(0); if (magic != MARSHAL_MAGIC_SMALL) { throw new Exception("bad marshal magic"); @@ -246,6 +406,27 @@ public class Jocaml { System.out.println(objs); } + + public void disassemble() throws Exception { + this.data.order(ByteOrder.LITTLE_ENDIAN); + this.data.position(0); + while (this.data.position() < this.data.capacity()) { + int op = this.data.getInt(); + String rep = null; + for (CamlInst inst : CamlInst.values()) { + if (inst.code == op) { + rep = inst.name(); + for (int i = 0; i < inst.numArgs; i++) { + rep += " " + this.data.getInt(); + } + } + } + if (rep == null) { + rep = ""; + } + System.out.println(rep); + } + } } public static Section findSection(Section[] sections, String name) { @@ -295,5 +476,6 @@ public class Jocaml { findSection(sections, "SYMB").unmarshal(); findSection(sections, "CRCS").unmarshal(); findSection(sections, "DATA").unmarshal(); + findSection(sections, "CODE").disassemble(); } }