/* JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine Copyright (C) 2012-2013 Ian Preston This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Details (including contact information) can be found at: jpc.sourceforge.net or the developer website sourceforge.net/projects/jpc/ End of licence header */ package tools; import javax.swing.*; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; public class JPCControl extends EmulatorControl { private final Object pc; private final Method execute; private final Method setState; private final Method state; private final Method ints; private final Method instructionInfo; private final Method setPhysicalMemory; private final Method disam; private final Method x86Length; private final Method getPage; private final Method destroy; private final URLClassLoader cl1; public JPCControl(String jar, String pcName, String[] extraArgs) throws IOException { this(jar, concat(CompareToBochs.possibleArgs.get(pcName), extraArgs)); } public JPCControl(String jar, String[] args) throws IOException { this(jar, args, false, false); } public JPCControl(String jar, String[] args, boolean showScreen, boolean disablePIT) throws IOException { URL[] urls1 = new URL[]{new File(jar).toURL()}; cl1 = new URLClassLoader(urls1, EmulatorControl.class.getClassLoader()); try { Class opts = cl1.loadClass("org.jpc.j2se.Option"); Method parse = opts.getMethod("parse", String[].class); String[] pcargs = args; if (disablePIT) pcargs = concat(new String[]{"-bochs"}, args); parse.invoke(opts, (Object)pcargs); Class c1 = cl1.loadClass("org.jpc.emulator.PC"); Constructor ctor = c1.getConstructor(String[].class); pc = ctor.newInstance((Object)pcargs); ints = c1.getMethod("checkInterrupts", Integer.class, Boolean.class); state = c1.getMethod("getState"); setState = c1.getMethod("setState", int[].class); execute = c1.getMethod("executeBlock"); instructionInfo = c1.getMethod("getInstructionInfo", Integer.class); setPhysicalMemory = c1.getMethod("setPhysicalMemory", Integer.class, byte[].class); disam = c1.getMethod("disam", byte[].class, Integer.class, Boolean.class); x86Length = c1.getMethod("x86Length", byte[].class, Boolean.class); destroy = c1.getMethod("destroy"); getPage = c1.getMethod("savePage", Integer.class, byte[].class, Boolean.class); Method startClock = c1.getMethod("start"); startClock.invoke(pc); if (showScreen) { JPanel screen = (JPanel)c1.getMethod("getNewMonitor").invoke(pc); JFrame frame = new JFrame(); frame.getContentPane().add("Center", new JScrollPane(screen)); frame.validate(); frame.setVisible(true); frame.setBounds(100, 100, 760, 500); } } catch (ClassNotFoundException e) {throw new RuntimeException(e.getMessage());} catch (NoSuchMethodException e) {throw new RuntimeException(e.getMessage());} catch (IllegalAccessException e) {throw new RuntimeException(e.getMessage());} catch (InvocationTargetException e) {throw new RuntimeException(e.getMessage());} catch (InstantiationException e) {throw new RuntimeException(e.getMessage());} } public String disam(byte[] code, Integer ops, Boolean is32Bit) { try { return (String) disam.invoke(pc, code, ops, is32Bit); } catch (InvocationTargetException e) { if (e.getCause().getMessage().contains("Invalid")) return "invalid"; return "Error during disam: " + e.getMessage(); } catch (IllegalAccessException e) {throw new RuntimeException(e.getMessage());} } public int x86Length(byte[] code, Boolean is32Bit) { try { return (Integer) x86Length.invoke(pc, code, is32Bit); } catch (InvocationTargetException e) { return 0; } catch (IllegalAccessException e) {throw new RuntimeException(e.getMessage());} } public String executeInstruction() throws IOException { try { ints.invoke(pc, new Integer(1), new Boolean(false)); int blockLength = (Integer)execute.invoke(pc); if (blockLength > 1) ints.invoke(pc, new Integer(blockLength - 1), new Boolean(false)); return (String) instructionInfo.invoke(pc, new Integer(blockLength)); } catch (InvocationTargetException e) { Throwable c = e.getCause(); if (c instanceof IllegalStateException) return c.getMessage(); if ((c != null) && c.toString().contains("PAGE_FAULT")) return c.toString(); throw new RuntimeException(e.getMessage()); } catch (IllegalAccessException e) { throw new RuntimeException(e.getMessage()); } } public int[] getState() throws IOException { try { return (int[])state.invoke(pc); } catch (InvocationTargetException e) {throw new RuntimeException(e.getMessage());} catch (IllegalAccessException e) {throw new RuntimeException(e.getMessage());} } public void setPhysicalMemory(int addr, byte[] data) throws IOException { try { setPhysicalMemory.invoke(pc, new Integer(addr), data); } catch (InvocationTargetException e) {throw new RuntimeException(e.getMessage());} catch (IllegalAccessException e) {throw new RuntimeException(e.getMessage());} } //public void setState(int[] state, int currentCSEIP) throws IOException //{ // try { // setState.invoke(pc, (int[])state); // } catch (InvocationTargetException e) {throw new RuntimeException(e.getMessage());} // catch (IllegalAccessException e) {throw new RuntimeException(e.getMessage());} //} public void destroy() { try { destroy.invoke(pc); } catch (InvocationTargetException e) { throw new RuntimeException(e.getMessage()); } catch (IllegalAccessException e) {throw new RuntimeException(e.getMessage());} } public Integer getPhysicalPage(Integer page, byte[] data) throws IOException { try { return (Integer) getPage.invoke(pc, page, data, new Boolean(false)); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return 0; } public Integer getLinearPage(Integer page, byte[] data) throws IOException { try { return (Integer) getPage.invoke(pc, page, data, new Boolean(true)); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return 0; } public byte[] getCMOS() throws IOException { throw new IllegalStateException("Unimplemented!"); } public int[] getPit() throws IOException { throw new IllegalStateException("Unimplemented!"); } public int getPITIntTargetEIP() throws IOException { throw new IllegalStateException("Unimplemented!"); } public void keysDown(String keys) { throw new IllegalStateException("Unimplemented!"); } public void keysUp(String keys) { throw new IllegalStateException("Unimplemented!"); } public void sendMouse(Integer dx, Integer dy, Integer dz, Integer buttons) { throw new IllegalStateException("Unimplemented!"); } public static <T> T[] concat(T[] first, T[] second) { T[] result = Arrays.copyOf(first, first.length + second.length); System.arraycopy(second, 0, result, first.length, second.length); return result; } }