From: <mic...@us...> - 2007-04-24 18:16:44
|
Revision: 90 http://svn.sourceforge.net/pearcolator/?rev=90&view=rev Author: michael_baer Date: 2007-04-24 11:16:44 -0700 (Tue, 24 Apr 2007) Log Message: ----------- - First version that runs ARM "Hello World" (compiled with libc) - Fixed several bugs related to ARM flags - Introduced the munmap system call within for the ARM ABI - Calls to memory.map may provide non-page aligned memory addresses - Introduced the stat64 structure Modified Paths: -------------- src/org/binarytranslator/Main.java src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java src/org/binarytranslator/arch/arm/decoder/Utils.java src/org/binarytranslator/arch/arm/os/abi/linux/ARM_LinuxSystemCalls.java src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java src/org/binarytranslator/arch/arm/os/process/linux/abi/EABI.java src/org/binarytranslator/arch/arm/os/process/linux/abi/Legacy.java src/org/binarytranslator/generic/memory/DebugMemory.java src/org/binarytranslator/generic/memory/IntAddressedMemory.java src/org/binarytranslator/generic/memory/Memory.java src/org/binarytranslator/generic/os/abi/linux/LinuxStructureFactory.java src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java Modified: src/org/binarytranslator/Main.java =================================================================== --- src/org/binarytranslator/Main.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/Main.java 2007-04-24 18:16:44 UTC (rev 90) @@ -10,6 +10,7 @@ import java.io.File; +import org.binarytranslator.arch.arm.decoder.Utils; import org.binarytranslator.generic.execution.DynamicTranslationController; import org.binarytranslator.generic.execution.ExecutionController; import org.binarytranslator.generic.execution.GdbController; @@ -93,17 +94,19 @@ System.out.println("***** INITIAL PROCESS SPACE *****\n"); System.out.println(ps); } - + //Create an execution controller and pass execution on to it ExecutionController controller; - if (DBT_Options.gdbStub) { + /*if (DBT_Options.gdbStub) { controller = new GdbController(DBT_Options.gdbStubPort, ps); } else { controller = new DynamicTranslationController(ps); - } + }*/ + controller = new InterpreterController(ps); + controller.run(); } } Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Interpreter.java 2007-04-24 18:16:44 UTC (rev 90) @@ -107,13 +107,13 @@ return regs.isNegativeSet() == regs.isOverflowSet(); case GT: - return (regs.isNegativeSet() == regs.isOverflowSet()) && regs.isZeroSet(); + return (regs.isNegativeSet() == regs.isOverflowSet()) && !regs.isZeroSet(); case HI: return regs.isCarrySet() && !regs.isZeroSet(); case LE: - return regs.isZeroSet() || (regs.isNegativeSet() == regs.isOverflowSet()); + return regs.isZeroSet() || (regs.isNegativeSet() != regs.isOverflowSet()); case LS: return !regs.isCarrySet() || regs.isZeroSet(); @@ -347,8 +347,8 @@ if (updateConditionCodes) { if (Rd != 15) { int result = lhs - rhs; - boolean carry = !(lhs < rhs); - boolean overflow = Utils.signedAddOverflow(lhs, -rhs); + boolean carry = !Utils.unsignedSubOverflow(lhs, rhs); + boolean overflow = Utils.signedSubOverflow(lhs, rhs); regs.setFlags(result < 0, result == 0, carry, overflow); } else { Modified: src/org/binarytranslator/arch/arm/decoder/Utils.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/Utils.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/arch/arm/decoder/Utils.java 2007-04-24 18:16:44 UTC (rev 90) @@ -2,7 +2,7 @@ import org.binarytranslator.DBT; -class Utils { +public class Utils { /** * Checks if a bit is set within a word. @@ -54,33 +54,124 @@ /** * Returns true, if the addition of both operands as unsigned integers will cause an overflow. - * This basically checks <code> operand1 + operand2 > Integer.MAX_VALUE</code>. + * At the moment, this converts both values to longs and checks if the 33rd bit (which actually represents the carry) + * overflows. */ - static boolean unsignedAddOverflow(int operand1, int operand2) { - return operand1 > Integer.MAX_VALUE - operand2; + public static boolean unsignedAddOverflow(int operand1, int operand2) { + long value1 = (long)operand1 & 0xFFFFFFFFL; + long value2 = (long)operand2 & 0xFFFFFFFFL; + + return ((value1 + value2) & 0x100000000L) != 0; } /** - * Returns true, if the subtraction of both operand1 - operand2 (both unsigned) will be a negative number. - * That only happens when <code>operand1 < operand2</code> + * Returns true, if the subtraction of both operand1 - operand2 (both unsigned) will issue a borrow. */ - static boolean unsignedSubOverflow(int operand1, int operand2) { + public static boolean unsignedSubOverflow(int operand1, int operand2) { + operand1 += Integer.MIN_VALUE; + operand2 += Integer.MIN_VALUE; + return operand1 < operand2; } /** - * Returns true, if the addition of both operands as unsigned integers will cause an overflow. - * The algorithm for this code was taken from http://msdn2.microsoft.com/en-us/library/ms972705.aspx. + * Returns true, if the addition of both operands as signed integers will cause an overflow. + * This basically checks <code>operand1 + operand2 > Integer.MAX_VALUE</code>. */ - static boolean signedAddOverflow(int operand1, int operand2) { - //overflow can only occur when both signs differ - if ((operand1 ^ operand2) >= 0) { - return false; + public static boolean signedAddOverflow(int operand1, int operand2) { + return operand1 > Integer.MAX_VALUE - operand2; + } + + /** + * Returns true, if the subtraction of operand1 from operand (as signed integers) + * will cause an overflow. + * This basically checks <code>operand1 - operand2 < Integer.MIN_VALUE</code>. + */ + public static boolean signedSubOverflow(int operand1, int operand2) { + // if the MSB is already set in any of the operands, then no overflow can + // occur + if (operand1 >= 0) { + return (operand2 < 0) && ((operand1-operand2) < 0); } + else { + return (operand2 > 0) && ((operand1-operand2) > 0); + } + } + + /** + * Performs a number of sanity tests that make sure that the above functions are working the + * manner described before.*/ + public static void runSanityTests() { + if (!Utils.unsignedAddOverflow(1, -1)) { + throw new RuntimeException("Error"); + } - if (operand1 < 0) - return operand1 < Integer.MIN_VALUE - operand2; - else - return Integer.MAX_VALUE - operand1 < operand2; + if (!Utils.unsignedAddOverflow(-1, -1)) { + throw new RuntimeException("Error"); + } + + if (!Utils.unsignedAddOverflow(-1, 1)) { + throw new RuntimeException("Error"); + } + + if (Utils.unsignedAddOverflow(10000, 10000)) { + throw new RuntimeException("Error"); + } + + if (Utils.unsignedSubOverflow(-1, 1)) { + throw new RuntimeException("Error"); + } + + if (!Utils.unsignedSubOverflow(1, -1)) { + throw new RuntimeException("Error"); + } + + if (Utils.unsignedSubOverflow(-1, -1)) { + throw new RuntimeException("Error"); + } + + if (Utils.unsignedSubOverflow(10, 0)) { + throw new RuntimeException("Error"); + } + + if (!Utils.unsignedSubOverflow(0, 10)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedAddOverflow(0x70000000, 0x10000000)) { + throw new RuntimeException("Error"); + } + + if (Utils.signedAddOverflow(0x90000000, 0x10000000)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedAddOverflow(0x50000000, 0x50000000)) { + throw new RuntimeException("Error"); + } + + if (Utils.signedAddOverflow(0x60000000, 0x10000000)) { + throw new RuntimeException("Error"); + } + + if (Utils.signedAddOverflow(0x10000000, 0x60000000)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedSubOverflow(0x80000000, 0x30000000)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedSubOverflow(0x30000000, 0x80000000)) { + throw new RuntimeException("Error"); + } + + if (!Utils.signedSubOverflow(0, 0x80000000)) { + throw new RuntimeException("Error"); + } + + if (Utils.signedSubOverflow(0, 0x70000000)) { + throw new RuntimeException("Error"); + } } } Modified: src/org/binarytranslator/arch/arm/os/abi/linux/ARM_LinuxSystemCalls.java =================================================================== --- src/org/binarytranslator/arch/arm/os/abi/linux/ARM_LinuxSystemCalls.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/arch/arm/os/abi/linux/ARM_LinuxSystemCalls.java 2007-04-24 18:16:44 UTC (rev 90) @@ -1,11 +1,14 @@ package org.binarytranslator.arch.arm.os.abi.linux; +import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; import org.binarytranslator.generic.os.abi.linux.LinuxSystemCallGenerator; import org.binarytranslator.generic.os.abi.linux.LinuxSystemCalls; public class ARM_LinuxSystemCalls extends LinuxSystemCalls { - public ARM_LinuxSystemCalls(LinuxSystemCallGenerator src) { + private final ARM_LinuxProcessSpace ps; + + public ARM_LinuxSystemCalls(ARM_LinuxProcessSpace ps, LinuxSystemCallGenerator src) { super(src); systemCallTable[1] = new LinuxSystemCalls.SysExit(); @@ -19,6 +22,7 @@ systemCallTable[49] = new LinuxSystemCalls.SysGetEUID(); systemCallTable[50] = new LinuxSystemCalls.SysGetEGID(); systemCallTable[90] = new LinuxSystemCalls.SysMmap(); + systemCallTable[91] = new LinuxSystemCalls.SysMunmap(); systemCallTable[122] = new LinuxSystemCalls.SysUname(); systemCallTable[146] = new LinuxSystemCalls.SysWriteV(); systemCallTable[197] = new LinuxSystemCalls.SysFstat64(); @@ -28,8 +32,16 @@ systemCallTable[202] = new LinuxSystemCalls.SysGetEGID(); systemCallTable[221] = new LinuxSystemCalls.SysFcntl64(); systemCallTable[252] = new LinuxSystemCalls.SysExitGroup(); + + this.ps = ps; } + + @Override + public void doSysCall() { + super.doSysCall(); + } + @Override protected String getMachine() { //TODO: Grab this from a real machine Modified: src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/arch/arm/os/process/ARM_Registers.java 2007-04-24 18:16:44 UTC (rev 90) @@ -4,6 +4,7 @@ public final class ARM_Registers { + public final static int FP = 11; public final static int SP = 13; public final static int LR = 14; public final static int PC = 15; Modified: src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-04-24 18:16:44 UTC (rev 90) @@ -28,18 +28,13 @@ private static final int STACK_TOP = 0xC0000000; /** - * The top of the bss segment - */ - private int brk; - - /** * Auxiliary vector */ private int[] auxVector; public ARM_LinuxProcessSpace() { - sysCallGenerator = new Legacy(this); - sysCalls = new ARM_LinuxSystemCalls(sysCallGenerator); + sysCallGenerator = new Legacy(this, 0xEBADADD); + sysCalls = new ARM_LinuxSystemCalls(this, sysCallGenerator); } @Override @@ -54,31 +49,52 @@ @Override public void initialise(Loader loader, int pc, int brk) { registers.set(ARM_Registers.PC, pc); - this.brk = brk; + sysCallGenerator.setBrk(brk); // initialize the stack - auxVector = new int[]{//LinuxStackInitializer.AuxiliaryVectorType.AT_SYSINFO, 0xffffe400, - //LinuxStackInitializer.AuxiliaryVectorType.AT_SYSINFO_EHDR, 0xffffe000, - LinuxStackInitializer.AuxiliaryVectorType.AT_HWCAP, 0x78bfbff, - LinuxStackInitializer.AuxiliaryVectorType.AT_PAGESZ, 0x1000, - LinuxStackInitializer.AuxiliaryVectorType.AT_CLKTCK, 0x64, - LinuxStackInitializer.AuxiliaryVectorType.AT_PHDR, ((ELF_Loader)loader).getProgramHeaderAddress(), - LinuxStackInitializer.AuxiliaryVectorType.AT_PHNUM, ((ELF_Loader)loader).elfHeader.getNumberOfProgramSegmentHeaders(), - LinuxStackInitializer.AuxiliaryVectorType.AT_BASE, 0x0, + auxVector = new int[] { + LinuxStackInitializer.AuxiliaryVectorType.AT_HWCAP, 0x97, + LinuxStackInitializer.AuxiliaryVectorType.AT_PAGESZ, 4096, //0x100 + LinuxStackInitializer.AuxiliaryVectorType.AT_CLKTCK, 0x17, + LinuxStackInitializer.AuxiliaryVectorType.AT_PHDR, 0x8034, + LinuxStackInitializer.AuxiliaryVectorType.AT_PHENT, 0x20, + LinuxStackInitializer.AuxiliaryVectorType.AT_PHNUM, 0x6, + LinuxStackInitializer.AuxiliaryVectorType.AT_BASE, 0x40000000, LinuxStackInitializer.AuxiliaryVectorType.AT_FLAGS, 0x0, - LinuxStackInitializer.AuxiliaryVectorType.AT_ENTRY, pc, + LinuxStackInitializer.AuxiliaryVectorType.AT_ENTRY, 0x82b4, + LinuxStackInitializer.AuxiliaryVectorType.AT_UID, 0x0, + LinuxStackInitializer.AuxiliaryVectorType.AT_EUID, 0x0, + LinuxStackInitializer.AuxiliaryVectorType.AT_GID, 0x0, + LinuxStackInitializer.AuxiliaryVectorType.AT_EGID, 0x0, + LinuxStackInitializer.AuxiliaryVectorType.AT_PLATFORM, 0xbffffecd }; - LinuxStackInitializer.AuxiliaryVectorType.AT_UID, DBT_Options.UID, - LinuxStackInitializer.AuxiliaryVectorType.AT_EUID, DBT_Options.UID, - LinuxStackInitializer.AuxiliaryVectorType.AT_GID, DBT_Options.GID, - LinuxStackInitializer.AuxiliaryVectorType.AT_EGID, DBT_Options.GID, - - LinuxStackInitializer.AuxiliaryVectorType.AT_SECURE, 0, - //LinuxStackInitializer.AuxiliaryVectorType.AT_PLATFORM, LinuxStackInitializer.AuxiliaryVectorType.STACK_TOP - getPlatformString().length, - LinuxStackInitializer.AuxiliaryVectorType.AT_NULL, 0x0}; - registers.set(ARM_Registers.SP, LinuxStackInitializer.stackInit(memory, STACK_TOP, getEnvironmentVariables(), auxVector)); } + + public void dumpStack() { + //grab the current frame pointer + int fp = registers.get(ARM_Registers.FP); + + //print the current position + System.out.println("PC: 0x" + Integer.toHexString(registers.get(ARM_Registers.PC))); + + //we might be in a leaf function which did not create a stack frame. Check that by + //comparing the current link register with the one saved on the first stack frame + int saved_lr = memory.load32(fp - 4); + int processor_lr = registers.get(ARM_Registers.LR); + + if (saved_lr != processor_lr) { + //we are in a leaf function that did not generate a stack frame. Print out the function address + System.out.println("Called from 0x" + Integer.toHexString(processor_lr - 4) + " (Function did not create a stack frame)."); + } + + do { + saved_lr = memory.load32(fp - 4); //load the link register, so we know where we're called from + fp = memory.load32(fp - 12); //load the previous frame pointer + System.out.println("Called from 0x" + Integer.toHexString(saved_lr - 4)); + } + while (fp != 0); + } @Override public GdbTarget getGdbTarget() { Modified: src/org/binarytranslator/arch/arm/os/process/linux/abi/EABI.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/abi/EABI.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/arch/arm/os/process/linux/abi/EABI.java 2007-04-24 18:16:44 UTC (rev 90) @@ -1,6 +1,7 @@ package org.binarytranslator.arch.arm.os.process.linux.abi; import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; +import org.binarytranslator.generic.memory.MemoryMapException; import org.binarytranslator.generic.os.abi.linux.LinuxSystemCallGenerator; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -28,15 +29,16 @@ /** The process space that we're running on. */ private final ARM_LinuxProcessSpace ps; private final ArgumentIterator args; + private int brk; - public EABI(ARM_LinuxProcessSpace ps) { + public EABI(ARM_LinuxProcessSpace ps, int brk) { this.ps = ps; + this.brk = brk; this.args = new ArgumentIterator(); } public int getBrk() { - // TODO Auto-generated method stub - throw new RuntimeException("Not yet implemented."); + return brk; } public ProcessSpace getProcessSpace() { @@ -53,8 +55,16 @@ } public void setBrk(int address) { -// TODO Auto-generated method stub - throw new RuntimeException("Not yet implemented."); + + try { + ps.memory.ensureMapped(brk, address); + } catch (MemoryMapException e) { + throw new Error(String.format( + "Error changing top of BSS from 0x%x to address 0x%x", brk, address), + e); + } + + brk = address; } public void setSysCallError(int r) { Modified: src/org/binarytranslator/arch/arm/os/process/linux/abi/Legacy.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/abi/Legacy.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/arch/arm/os/process/linux/abi/Legacy.java 2007-04-24 18:16:44 UTC (rev 90) @@ -4,6 +4,7 @@ import org.binarytranslator.arch.arm.decoder.ARM_InstructionDecoder; import org.binarytranslator.arch.arm.decoder.ARM_Instructions; import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; +import org.binarytranslator.generic.memory.MemoryMapException; import org.binarytranslator.generic.os.abi.linux.LinuxSystemCallGenerator; import org.binarytranslator.generic.os.process.ProcessSpace; @@ -30,21 +31,29 @@ /** A re-used iterator that allows enumerating the argument of the current * system call */ private final ArgumentIterator syscallArgs; + + private int brk; - public Legacy(ARM_LinuxProcessSpace ps) { + public Legacy(ARM_LinuxProcessSpace ps, int brk) { this.ps = ps; + this.brk = brk; syscallArgs = new ArgumentIterator(); } public int getBrk() { -// TODO Auto-generated method stub - throw new RuntimeException("Not yet implemented."); + return brk; } public void setBrk(int address) { -// TODO Auto-generated method stub - throw new RuntimeException("Not yet implemented."); + try { + ps.memory.ensureMapped(brk, address); + } catch (MemoryMapException e) { + throw new Error("Error changing top of BSS to address 0x"+Integer.toHexString(address)+ + " from 0x" + Integer.toHexString(brk), e); + } + + brk = address; } public ProcessSpace getProcessSpace() { Modified: src/org/binarytranslator/generic/memory/DebugMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/DebugMemory.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/generic/memory/DebugMemory.java 2007-04-24 18:16:44 UTC (rev 90) @@ -10,6 +10,8 @@ import java.io.RandomAccessFile; import java.nio.channels.FileChannel; + +import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; import org.binarytranslator.vmInterface.TranslationHelper; import org.jikesrvm.compilers.opt.ir.OPT_Operand; @@ -121,10 +123,21 @@ */ public int map(int addr, int len, boolean read, boolean write, boolean exec) throws MemoryMapException { - // Check address is page aligned + // Check that the address is page aligned if ((addr % PAGE_SIZE) != 0) { - MemoryMapException.unalignedAddress(addr); + // if it is not, truncate the address down to the next page boundary and + // start mapping from there + int validPageCount = addr / PAGE_SIZE; + int oldStartAddress = addr; + addr = validPageCount * PAGE_SIZE; + + if (DBT.VerifyAssertions) + DBT._assert(oldStartAddress > addr); + + // we have to map more more memory now to reach the same end address + len += (oldStartAddress - addr); } + // Create memory int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; byte pages[][] = new byte[num_pages][PAGE_SIZE]; Modified: src/org/binarytranslator/generic/memory/IntAddressedMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedMemory.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/generic/memory/IntAddressedMemory.java 2007-04-24 18:16:44 UTC (rev 90) @@ -10,6 +10,7 @@ import java.io.RandomAccessFile; +import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; import org.jikesrvm.VM_Configuration; @@ -191,10 +192,21 @@ */ public int map(int addr, int len, boolean read, boolean write, boolean exec) throws MemoryMapException { - // Check address is page aligned + // Check that the address is page aligned if ((addr % PAGE_SIZE) != 0) { - MemoryMapException.unalignedAddress(addr); + // if it is not, truncate the address down to the next page boundary and + // start mapping from there + int validPageCount = addr / PAGE_SIZE; + int oldStartAddress = addr; + addr = validPageCount * PAGE_SIZE; + + if (DBT.VerifyAssertions) + DBT._assert(oldStartAddress > addr); + + // we have to map more more memory now to reach the same end address + len += (oldStartAddress - addr); } + // Calculate number of pages int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; // Create memory Modified: src/org/binarytranslator/generic/memory/Memory.java =================================================================== --- src/org/binarytranslator/generic/memory/Memory.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/generic/memory/Memory.java 2007-04-24 18:16:44 UTC (rev 90) @@ -251,4 +251,41 @@ throw new Error("Error linking method at " + callAddress + " for memory model " + this.getClass()); } + + /** + * Helper function that prints a hexadecimal version of a memory region. + * Quite useful for debugging. + * @param address + * The address to start printing from. + * @param length + * The number of bytes to print from <code>address</code>. + * @return + * A string with a hexdecimal representation of that memory region. + * The string is only useful for printing, no assumptions about its format + * shall be made. + */ + public String hexDump(int address, int length) { + + StringBuilder output = new StringBuilder(); + int printed = 0; + + while (printed != length) { + + //make a line break and print the current address every 8 bytes + if (printed % 8 == 0) { + if (printed != 0) + output.append('\n'); + + output.append("[0x"); + output.append(Integer.toHexString(address)); + output.append("] "); + } + + output.append(String.format("%02x", loadUnsigned8(address++))); + output.append(' '); + printed++; + } + + return output.toString(); + } } \ No newline at end of file Modified: src/org/binarytranslator/generic/os/abi/linux/LinuxStructureFactory.java =================================================================== --- src/org/binarytranslator/generic/os/abi/linux/LinuxStructureFactory.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/generic/os/abi/linux/LinuxStructureFactory.java 2007-04-24 18:16:44 UTC (rev 90) @@ -5,17 +5,28 @@ import org.binarytranslator.generic.memory.Memory; -/** Namespace for all structures. */ +/** + * Linux heavily uses certain c-structs when to pass parameters for system calls. + * To allow the pearcolator linux ABIs to share a common set of structure definitions, this + * namespace provides a factory for Java representations of the most commonly used structures. + * Each structure provides methods to read the structure from or write it to memory. + * + * @author Michael Baer + */ public class LinuxStructureFactory { + /** A factory method which will create a stat64 structure.*/ public final stat64 new_stat64() { return new stat64(); } + /** + * The stat64 structure, as defined in <code>include\linux\stat64.h</code>. + */ public class stat64 extends Structure { @_unsigned short st_dev; @_unsigned @_padding(10) byte __pad0; - @_unsigned @_long long __st_ino; + @_unsigned long __st_ino; @_unsigned int st_mode; @_unsigned int st_nlink; @_unsigned long st_uid; @@ -34,11 +45,80 @@ @_unsigned @_padding(1) long __pad7; @_unsigned @_long long st_ino; - public stat64() { + /** + * At the moment, we have to enumerate the members of a structure in the constructor + * (in the order of definition within the c file), because the JVM specs say that no code shall + * rely on the order of the fields returned by reflection methods (namely {@link Class#getFields()}. + * + * Therefore, we have to persist the order of fields, which is why we are enumerating them again. + * However, this is not necessary the final solution. Possibly we're going to introduce a + * Java annotation that keeps the information about the order - or we might even solve the problem + * completely differently. + * + */ + protected stat64() { super(new String[]{ "st_dev", "__pad0", "__st_ino", "st_mode", "st_nlink", "st_uid", "st_gid", "st_rdev", "__pad3", "st_size", "st_blksize", "st_blocks", "__pad4", "st_atime", "__pad5", "st_mtime", "__pad6", "st_ctime", "__pad7", "st_ino"}); } + + /** This overriden structure enables Michael to debug the pearcolator in windows. + * Otherwise, it should not be used, which is why it is deprecated. */ + @Override + @Deprecated + public void read(Memory mem, int addr) { + StructureAdapter reader = createStructureAdapter(mem, addr); + + st_dev = reader.loadShort(); + reader.skipPadding(10); + __st_ino = reader.loadLong(); + st_mode = reader.loadInt(); + st_nlink = reader.loadInt(); + st_uid = reader.loadLong(); + st_gid = reader.loadLong(); + st_rdev = reader.loadShort(); + reader.skipPadding(10); + st_size = reader.loadLongLong(); + st_blksize = reader.loadLong(); + st_blocks = reader.loadLong(); + __pad4 = reader.loadLong(); + st_atime = reader.loadLong(); + __pad5 = reader.loadLong(); + st_mtime = reader.loadLong(); + __pad6 = reader.loadLong(); + st_ctime = reader.loadLong(); + __pad7 = reader.loadLong(); + st_ino = reader.loadLongLong(); + } + + /** + * This overriden structure enables Michael to debug the pearcolator in windows. + * Otherwise, it should not be used, which is why it is deprecated. */ + @Override + @Deprecated + public void write(Memory mem, int addr) { + StructureAdapter writer = createStructureAdapter(mem, addr); + writer.storeShort(st_dev); + writer.skipPadding(10); + writer.storeLong(__st_ino); + writer.storeInt(st_mode); + writer.storeInt(st_nlink); + writer.storeLong(st_uid); + writer.storeLong(st_gid); + writer.storeShort(st_rdev); + writer.skipPadding(10); + writer.storeLongLong(st_size); + writer.storeLong(st_blksize); + writer.storeLong(st_blocks); + writer.storeLong(__pad4); + writer.storeLong(st_atime); + writer.storeLong(__pad5); + writer.storeLong(st_mtime); + writer.storeLong(__pad6); + writer.storeLong(st_ctime); + writer.storeLong(__pad7); + writer.storeLongLong(st_ino); + } } private @interface _long {} @@ -50,9 +130,18 @@ /** A list of all structure members in the order that they appear in the source code. */ protected Field[] members; + /** + * This constructor is uncommented because reflection does not work when debugging pearcolator + * under windows, which is what I (=Michael Baer) am currently doing. + * + * However, as soon as this is done, the deprecated-tag shall be removed and the code in this + * function be uncommented. + * @param memberNames + */ + @Deprecated protected Structure(String[] memberNames) { - Class myType = getClass(); + /*Class myType = getClass(); members = new Field[memberNames.length]; for (int i = 0; i < memberNames.length; i++) { @@ -63,9 +152,17 @@ catch (NoSuchFieldException e) { throw new RuntimeException("Invalid field: " + memberNames[i] + " in struct: " + myType.getSimpleName(), e); } - } + }*/ } + /** + * Read all members of this structure from memory into the structure. + * + * @param mem + * The memory that the structure is read from. + * @param addr + * The address of the structure's beginning in the memory. + */ public void read(Memory mem, int addr) { // get a structure writer, which will keep track of the object offsets @@ -112,6 +209,14 @@ } } + /** + * Writes the contents of the structure from its members into memory. + * + * @param mem + * The Memory into which the structure shall be written. + * @param addr + * The address, to which the structure is written. + */ public void write(Memory mem, int addr) { // get a structure writer, which will keep track of the object offsets @@ -165,6 +270,8 @@ } } + /** + * Converts a structure into a c-like, human readable format */ @Override public String toString() { @@ -193,10 +300,32 @@ } } + /** + * A factory method that creates a {@link StructureAdapter}. StructureAdapters are used to + * encapsulate the architecture specifics (like <code>sizeof(int)</code> and padding) when + * reading a structure. + * + * Implement your own StructureAdapter when you need to override the default implementations of + * how a structure is being read, while still keeping the default structures defined here. + * + * @param mem + * @param addr + * @return + */ protected final StructureAdapter createStructureAdapter(Memory mem, int addr) { - return new DefaultStructureAdapter(mem, addr); + return new StructureAdapter_32Bit(mem, addr); } + /** + * A StructureAdapter abstracts the properties (size, padding, maybe endianess) of the elements + * within a structure. Provide an own implementation of this class when the default data sizes + * and member alignments are not suitable for your architecture. + * + * Structures are always being read in the order of element definition. Therefore, any implementation + * of StructureAdapter can rely on the load/store functions being called in order, from the first + * to the last structure element. + * + */ protected static abstract class StructureAdapter { public abstract byte loadByte(); @@ -211,15 +340,51 @@ public abstract void storeLong(long value); public abstract void storeLongLong(long value); + /** + * Some structures contain rather large padding fields. To prevent use from reading these from + * memory byte-by-byte, this function may be used to skip a padding of type <code>field</code> + * that occurs <code>count</code> times. + * + * For example, when skipping a member like this <code>char pad[10]</char> the <code>field</code> + * would identify this as a char field, while the <code>count</code> member would say that we want + * to skip the char 10 times. + * + * @param field + * The type of the field that is being skipped. + * @param count + * The number of times this field as a padding in the structure. + */ public abstract void skipPadding(Field field, int count); + + /** + * This function is used temporarly to debug pearcolator in windows. However, + * it should normally not be invoked and as soon as windows-debugging is done, this + * function shall be removed from the source (along with all invokations of it).*/ + @Deprecated + public abstract void skipPadding(int count); } - protected static class DefaultStructureAdapter extends StructureAdapter { + /** + * A default implementation of a structure adapter. It has the following properties: + * + * <ul> + * <li>Every member is memory aligned to its size (i.e. a 4-byte data type is aligned to 4-byte + * boundaries</li> + * <li>The minimal needed amount of padding is inserted where the member is not already + * aligned to its size.</li> + * <li><code>sizeof(int) == 4</code></li> + * <li><code>sizeof(long) == 4</code></li> + * <li><code>sizeof(long long) == 8</code></li> + * <li><code>sizeof(short) == 2</code></li> + * <li><code>sizeof(byte) == 1</code></li> + * </ul> + */ + protected static class StructureAdapter_32Bit extends StructureAdapter { private final Memory mem; private int addr; - public DefaultStructureAdapter(Memory mem, int addr) { + public StructureAdapter_32Bit(Memory mem, int addr) { this.mem = mem; this.addr = addr; } @@ -350,5 +515,10 @@ return; } } + + @Override + public void skipPadding(int count) { + addr += count; + } } } Modified: src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java =================================================================== --- src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java 2007-04-23 22:12:34 UTC (rev 89) +++ src/org/binarytranslator/generic/os/abi/linux/LinuxSystemCalls.java 2007-04-24 18:16:44 UTC (rev 90) @@ -23,13 +23,13 @@ /** * The source of the system calls */ - private LinuxSystemCallGenerator src; + protected LinuxSystemCallGenerator src; /** Allows access to the system call's arguments */ - private LinuxSystemCallGenerator.CallArgumentIterator arguments; + protected LinuxSystemCallGenerator.CallArgumentIterator arguments; /** Allows access to a number of operating-system specific structures. */ - private LinuxStructureFactory structures; + protected LinuxStructureFactory structures; /** * Maximum number of system calls @@ -802,9 +802,18 @@ int fd = arguments.nextInt(); LinuxStructureFactory.stat64 buf = structures.new_stat64(); - buf.read(src.getProcessSpace().memory, arguments.nextInt()); - System.out.println(buf.toString()); + if (fd == 1) { + buf.st_mode = 0x2180; + buf.st_rdev = (short)0x8800; + buf.__st_ino = buf.st_ino = 2; + buf.st_blksize = 0x400; + } + else + throw new RuntimeException("Unimplemented system call."); + + buf.write(src.getProcessSpace().memory, arguments.nextInt()); + src.setSysCallReturn(0); } } @@ -893,8 +902,9 @@ int start = arguments.nextInt(); int length = arguments.nextInt(); - throw new Error("TODO!"); - //src.setSysCallReturn(src.munmap(start, length)); + + src.getProcessSpace().memory.unmap(start, length); + src.setSysCallReturn(0); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |