From: <mic...@us...> - 2007-08-27 15:14:37
|
Revision: 174 http://pearcolator.svn.sourceforge.net/pearcolator/?rev=174&view=rev Author: michael_baer Date: 2007-08-27 08:14:38 -0700 (Mon, 27 Aug 2007) Log Message: ----------- - Added support for Big and Little Endian Applications on ARM - Added memory implementations for big endian Modified Paths: -------------- rvmroot.patch src/org/binarytranslator/arch/arm/decoder/ARM_Options.java src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java src/org/binarytranslator/generic/os/loader/elf/ELF_File.java src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java Added Paths: ----------- src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java Modified: rvmroot.patch =================================================================== --- rvmroot.patch 2007-08-24 17:51:46 UTC (rev 173) +++ rvmroot.patch 2007-08-27 15:14:38 UTC (rev 174) @@ -146,7 +146,7 @@ [Lorg/jikesrvm/compilers/opt/OPT_Simplifier$DefUseEffect; [Lorg/jikesrvm/compilers/opt/ir/OPT_Operator; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ELF_Identity$AddressSize; -+[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ELF_Identity$ByteOrder; ++[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$ByteOrder; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$Header$ObjectFileType; +[Lorg/binarytranslator/generic/os/loader/elf/ELF_File$SegmentRange; +[Lorg/binarytranslator/vmInterface/DummyDynamicCodeRunner; @@ -157,4 +157,6 @@ +[Lorg/binarytranslator/arch/arm/decoder/ARM_Instructions$Instruction$Condition; +[Lorg/binarytranslator/arch/arm/decoder/ARM_Instructions$DataProcessing$Opcode; +[Lorg/binarytranslator/arch/arm/decoder/ARM_Instructions$OperandWrapper$ShiftType; ++[Lorg/binarytranslator/arch/arm/decoder/ARM_Laziness$Operation; ++[Lorg/binarytranslator/arch/arm/decoder/ARM_Laziness$Flag; \ No newline at end of file Modified: src/org/binarytranslator/arch/arm/decoder/ARM_Options.java =================================================================== --- src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/decoder/ARM_Options.java 2007-08-27 15:14:38 UTC (rev 174) @@ -1,5 +1,7 @@ package org.binarytranslator.arch.arm.decoder; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; + public class ARM_Options { public enum FlagBehaviour { @@ -39,6 +41,9 @@ /** Sets the memory model that ARM shall use. */ public static MemoryModel memoryModel = MemoryModel.IntAddressed; + /** Override the byte order read from the ELF file. */ + public static ByteOrder enforcedByteOrder = null; + public static void parseOption(String key, String value) { if (key.equalsIgnoreCase("optimizeByProfiling")) { optimizeTranslationByProfiling = Boolean.parseBoolean(value); @@ -50,7 +55,9 @@ memoryModel = ARM_Options.MemoryModel.valueOf(value); } else if (key.equalsIgnoreCase("optimizedFlags")) { useOptimizedFlags = Boolean.parseBoolean(value); - } + } else if (key.equalsIgnoreCase("byteOrder")) { + enforcedByteOrder = ByteOrder.valueOf(value); + } else { throw new Error("Unknown ARM option: " + key); } Modified: src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/os/process/ARM_ProcessSpace.java 2007-08-27 15:14:38 UTC (rev 174) @@ -10,9 +10,13 @@ import org.binarytranslator.arch.arm.os.process.linux.ARM_LinuxProcessSpace; import org.binarytranslator.generic.decoder.CodeTranslator; import org.binarytranslator.generic.decoder.Interpreter; +import org.binarytranslator.generic.memory.ByteAddressedBigEndianMemory; import org.binarytranslator.generic.memory.ByteAddressedLittleEndianMemory; +import org.binarytranslator.generic.memory.IntAddressedBigEndianMemory; import org.binarytranslator.generic.memory.IntAddressedLittleEndianMemory; import org.binarytranslator.generic.os.loader.Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; import org.binarytranslator.generic.os.process.ProcessSpace; import org.binarytranslator.vmInterface.DBT_Trace; import org.jikesrvm.compilers.opt.ir.OPT_GenerationContext; @@ -20,11 +24,9 @@ public abstract class ARM_ProcessSpace extends ProcessSpace { - /** Registers used by this process */ public ARM_Registers registers; - /** * Debug information * @@ -38,16 +40,44 @@ } } - protected ARM_ProcessSpace() { + protected ARM_ProcessSpace(ByteOrder byteOrder) { registers = new ARM_Registers(); switch (ARM_Options.memoryModel) { case ByteAddressed: - memory = new ByteAddressedLittleEndianMemory(); + + switch (byteOrder) + { + case LittleEndian: + memory = new ByteAddressedLittleEndianMemory(); + break; + + case BigEndian: + memory = new ByteAddressedBigEndianMemory(); + break; + + default: + throw new RuntimeException("Unexpected byte order: " + byteOrder); + } + break; case IntAddressed: - memory = new IntAddressedLittleEndianMemory(); + + switch (byteOrder) + { + case LittleEndian: + memory = new IntAddressedLittleEndianMemory(); + break; + + case BigEndian: + memory = new IntAddressedBigEndianMemory(); + break; + + default: + throw new RuntimeException("Unexpected byte order: " + byteOrder); + } + break; default: @@ -79,12 +109,30 @@ public static ProcessSpace createProcessSpaceFromBinary(Loader loader) throws IOException { Loader.ABI abi = loader.getABI(); + + //determine the byte order for the memory implementation + ByteOrder byteOrder = ARM_Options.enforcedByteOrder; + + if (byteOrder == null) { + if (loader instanceof ELF_Loader) { + //read the byte order from the elf file + byteOrder = ((ELF_Loader)loader).getFile().getByteOrder(); + } + else { + byteOrder = ByteOrder.LittleEndian; + System.err.println("WARNING: Unable to deduce byte order from binary file. Defaulting to " + byteOrder); + } + } + else { + System.err.println("WARNING: Overriding byte order set by ELF file to " + byteOrder); + } + if (abi == Loader.ABI.ARM) { report("Creating ARM Linux ABI Process space"); - return new ARM_LinuxProcessSpace(); + return new ARM_LinuxProcessSpace(byteOrder); } else { report("Creating ARM image process space."); - return new ARM_ImageProcessSpace(); + return new ARM_ImageProcessSpace(byteOrder); } } Modified: src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/os/process/image/ARM_ImageProcessSpace.java 2007-08-27 15:14:38 UTC (rev 174) @@ -10,6 +10,7 @@ import org.binarytranslator.generic.execution.GdbController.GdbTarget; import org.binarytranslator.generic.fault.InsufficientMemoryException; import org.binarytranslator.generic.os.loader.Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; public class ARM_ImageProcessSpace extends ARM_ProcessSpace { @@ -17,11 +18,8 @@ private final int STACK_SIZE = 4096 * 1000; private final int HEAP_SIZE = 4096 * 1000; - public ARM_ImageProcessSpace() { - super(); - - //make sure that pages of memory are automatically mapped in as they are requested. - //memory = new AutoMappingMemory(memory); + public ARM_ImageProcessSpace(ByteOrder byteOrder) { + super(byteOrder); } private int allocateFreeMemoryArea(int stackSize) throws InsufficientMemoryException Modified: src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java =================================================================== --- src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/arch/arm/os/process/linux/ARM_LinuxProcessSpace.java 2007-08-27 15:14:38 UTC (rev 174) @@ -10,6 +10,7 @@ import org.binarytranslator.generic.os.abi.linux.LinuxSystemCalls; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.loader.elf.ELF_Loader; +import org.binarytranslator.generic.os.loader.elf.ELF_File.ByteOrder; public class ARM_LinuxProcessSpace extends ARM_ProcessSpace { @@ -31,7 +32,9 @@ */ private int[] auxVector; - public ARM_LinuxProcessSpace() { + public ARM_LinuxProcessSpace(ByteOrder byteOrder) { + super(byteOrder); + sysCallGenerator = new Legacy(this); sysCalls = new ARM_LinuxSystemCalls(this, sysCallGenerator); } Added: src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/ByteAddressedBigEndianMemory.java 2007-08-27 15:14:38 UTC (rev 174) @@ -0,0 +1,550 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; + +/** + * ByteAddressedMemory: + * + * Memory is arrays of bytes, no endian conversion is performed. + * + * The string helo followed by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address| + * ----------------- + * .........07 | ca| + * .........06 | fe| + * .........05 | ba| + * .........04 | be| + * .........03 |'o'| + * .........02 |'l'| + * .........01 |'e'| + * .........00 |'H'| + * </pre> + */ +public class ByteAddressedBigEndianMemory extends CallBasedMemory { + + /** The size of a single page in bytes. */ + private static final int PAGE_SIZE = 4096; + + /** Bits in offset */ + private static final int OFFSET_BITS = 12; + + /** The number of pages */ + private static final int NUM_PAGES = 0x100000; + + /** The maximum amount of RAM available */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** The memory backing store */ + private byte readableMemory[][]; + private byte writableMemory[][]; + private byte executableMemory[][]; + + /** Do we have more optimal nio mmap operation? */ + private boolean HAVE_java_nio_FileChannelImpl_nio_mmap_file = false; + + /** + * Constructor - used when this is the instatiated class + */ + public ByteAddressedBigEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the name of the over-riding class + */ + protected ByteAddressedBigEndianMemory(Class classType) { + super(classType != null ? classType : ByteAddressedBigEndianMemory.class); + readableMemory = new byte[NUM_PAGES][]; + writableMemory = new byte[NUM_PAGES][]; + executableMemory = new byte[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + private static final int getOffset(int address) { + return address & (PAGE_SIZE - 1); + } + + /** + * Return the page table entry part of the address + */ + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Create memory + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + byte pages[][] = new byte[num_pages][PAGE_SIZE]; + + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + + if (DBT_Options.debugMemory) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate pages + readableMemory[pte + i] = read ? pages[i] : null; + writableMemory[pte + i] = write ? pages[i] : null; + executableMemory[pte + i] = exec ? pages[i] : null; + } + + return addr; + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + // Calculate number of pages + int num_pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugMemory) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + try { + // Get page table entry + int pte = getPTE(addr); + // Can we optimise the reads to use mmap? + if (!HAVE_java_nio_FileChannelImpl_nio_mmap_file) { + // Sub-optimal + file.seek(offset); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + // Allocate page + byte page[] = new byte[PAGE_SIZE]; + if (i == 0) { // first read, start from offset upto a page length + file.read(page, getOffset(addr), PAGE_SIZE - getOffset(addr)); + } else if (i == (num_pages - 1)) { // last read + file.read(page, 0, ((len - getOffset(addr)) % PAGE_SIZE)); + } else { + file.read(page); + } + + readableMemory[pte + i] = read ? page : null; + writableMemory[pte + i] = write ? page : null; + executableMemory[pte + i] = exec ? page : null; + } + } else { + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + // Allocate page + if (read && write) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_WRITE, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + writableMemory[pte + i] = readableMemory[pte + i]; + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (read) { + readableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + if (exec) { + executableMemory[pte + i] = readableMemory[pte + i]; + } + } else if (exec) { + executableMemory[pte + i] = file.getChannel().map( + FileChannel.MapMode.READ_ONLY, offset + (i * PAGE_SIZE), + PAGE_SIZE).array(); + } else { + throw new Error("Unable to map address 0x" + + Integer.toHexString(addr) + " with permissions " + + (read ? "r" : "-") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + } + } + return addr; + } catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private byte[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + final public int loadSigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadS8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)]; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + final public int loadUnsigned8(int addr) { + try { + if (DBT_Options.debugMemory) + System.err.println("LoadU8 address: 0x" + Integer.toHexString(addr) + + " val: " + readableMemory[getPTE(addr)][getOffset(addr)]); + return readableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } catch (NullPointerException e) { + System.err.println("Null pointer exception at address: 0x" + + Integer.toHexString(addr)); + throw e; + } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + return (loadSigned8(addr) << 8) | loadUnsigned8(addr + 1); + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + return (loadUnsigned8(addr) << 8) | loadUnsigned8(addr + 1); + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + try { + return (loadSigned8(addr) << 24) | (loadUnsigned8(addr + 1) << 16) + | (loadUnsigned8(addr + 2) << 8) | loadUnsigned8(addr + 3); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + if (DBT_Options.debugMemory) + System.err.println("LoadI8 address: 0x" + Integer.toHexString(addr) + + " val: " + executableMemory[getPTE(addr)][getOffset(addr)]); + return executableMemory[getPTE(addr)][getOffset(addr)] & 0xFF; + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + return (loadInstruction8(addr) << 24) + | (loadInstruction8(addr + 1) << 16) + | (loadInstruction8(addr + 2) << 8) | loadInstruction8(addr + 3); + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public final void store8(int addr, int value) { + if (DBT_Options.debugMemory) + System.err.println("Store8 address: 0x" + Integer.toHexString(addr) + + " val: 0x" + Integer.toHexString(value & 0xFF)); + writableMemory[getPTE(addr)][getOffset(addr)] = (byte) value; + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + store8(addr, value >> 8); + store8(addr + 1, value); + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + try { + store8(addr, value >> 24); + store8(addr + 1, value >> 16); + store8(addr + 2, value >> 8); + store8(addr + 3, value); + } catch (Exception e) { + throw new SegmentationFault(addr); + } + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + byte[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + @Override + public int loadInstruction16(int addr) { + return (loadInstruction8(addr) << 8) | loadInstruction8(addr + 1); + } +} Added: src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java (rev 0) +++ src/org/binarytranslator/generic/memory/IntAddressedBigEndianMemory.java 2007-08-27 15:14:38 UTC (rev 174) @@ -0,0 +1,669 @@ +/* + * This file is part of binarytranslator.org. The binarytranslator.org + * project is distributed under the Common Public License (CPL). + * A copy of the license is included in the distribution, and is also + * available at http://www.opensource.org/licenses/cpl1.0.php + * + * (C) Copyright Ian Rogers, The University of Manchester 2003-2006 + */ +package org.binarytranslator.generic.memory; + +import java.io.RandomAccessFile; + +import org.binarytranslator.DBT; +import org.binarytranslator.DBT_Options; +import org.binarytranslator.generic.fault.SegmentationFault; +import org.vmmagic.pragma.Inline; + +/** + * IntAddressedMemory: + * + * Memory is arrays of ints, no endian conversion is performed. + * + * The string helloworld following by the int of 0xcafebabe appear as: + * + * <pre> + * Byte Address + * Int Address | 0 | 1 | 2 | 3 | + * ----------------------------- + * .........0c | ca| fe| ba| be| + * .........08 |'l'|'d'| \n| \0| + * .........04 |'o'|'W'|'o'|'r'| + * .........00 |'H'|'e'|'l'|'l'| + * </pre> + */ +public class IntAddressedBigEndianMemory extends CallBasedMemory { + /** + * The size of pages + */ + protected static final int PAGE_SIZE = 4096; + + /** + * Bits in offset + */ + protected static final int OFFSET_BITS = 12; + + /** + * The number of pages + */ + protected static final int NUM_PAGES = 0x100000; + + /** + * The maximum amount of RAM available + */ + protected static final long MAX_RAM = (long) PAGE_SIZE * (long) NUM_PAGES; + + /** + * The memory backing store + */ + private int readableMemory[][]; + + private int writableMemory[][]; + + private int executableMemory[][]; + + /** + * Constructor - used when this is the instatiated class + */ + public IntAddressedBigEndianMemory() { + this(null); + } + + /** + * Constructor - used when deriving a class + * + * @param classType + * the type of the over-riding class + */ + protected IntAddressedBigEndianMemory(Class classType) { + super(classType != null ? classType : IntAddressedBigEndianMemory.class); + readableMemory = new int[NUM_PAGES][]; + writableMemory = new int[NUM_PAGES][]; + executableMemory = new int[NUM_PAGES][]; + } + + /** + * Return the offset part of the address + */ + @Inline + private static final int getOffset(int address) { + return (address & (PAGE_SIZE - 1)) >>> 2; + } + + /** + * Return the page table entry part of the address + */ + @Inline + private static final int getPTE(int address) { + return address >>> OFFSET_BITS; + } + + /** + * Is the given address mapped into memory? + * @param addr to check + * @return true => memory is mapped + */ + public boolean isMapped(int addr) { + return getPage(getPTE(addr)) != null; + } + + /** + * @return the size of a page + */ + public int getPageSize() { + return PAGE_SIZE; + } + + /** + * Is the given address aligned on a page boundary? + * + * @param addr + * the address to check + * @return whether the address is aligned + */ + public boolean isPageAligned(int addr) { + return (addr % PAGE_SIZE) == 0; + } + + /** + * Make the given address page aligned to the page beneath it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToPage(int addr) { + return (addr >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Make the given address page aligned to the page above it + * + * @param addr + * the address to truncate + * @return the truncated address + */ + public int truncateToNextPage(int addr) { + return ((addr + PAGE_SIZE - 1) >> OFFSET_BITS) << OFFSET_BITS; + } + + /** + * Find free consecutive pages + * + * @param pages + * the number of pages required + * @return the address found + */ + private final int findFreePages(int pages) { + starting_page_search: for (int i = 0; i < NUM_PAGES; i++) { + if (getPage(i) == null) { + int start = i; + int end = i + pages; + for (; i <= end; i++) { + if (getPage(i) != null) { + continue starting_page_search; + } + } + return start << OFFSET_BITS; + } + } + throw new Error( + "No mappable consecutive pages found for an anonymous map of size" + + (pages * PAGE_SIZE)); + } + + /** + * Map an anonymous page of memory + * + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public int map(int addr, int len, boolean read, boolean write, boolean exec) + throws MemoryMapException { + // Check that the address is page aligned + if ((addr % PAGE_SIZE) != 0) { + // 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 + int pages[][] = new int[num_pages][PAGE_SIZE / 4]; + // Find address if not specified + if (addr == 0) { + addr = findFreePages(num_pages); + } + if (DBT_Options.debugRuntime) { + System.out.println("Anonymous mapping: addr=0x" + + Integer.toHexString(addr) + " len=" + len + (read ? " r" : " -") + + (write ? "w" : "-") + (exec ? "x" : "-")); + } + // Get page table entry + int pte = getPTE(addr); + for (int i = 0; i < num_pages; i++) { + // Check pages aren't already allocated + if (getPage(pte + i) != null) { + throw new Error("Memory map of already mapped location addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + + readableMemory[pte+i] = read ? pages[i] : null; + writableMemory[pte+i] = write ? pages[i] : null; + executableMemory[pte+i] = exec ? pages[i] : null; + } + return addr; + } + + /** + * Returns the page currently mapped at the given page table entry. + * + * @param pte + * The page table entry, for which a page is to be retrieved. + * @return + * The page mapped at the given page table entry or null, if no page is currently mapped + * to that entry. + */ + private int[] getPage(int pte) { + + if (readableMemory[pte] != null) + return readableMemory[pte]; + + if (writableMemory[pte] != null) + return writableMemory[pte]; + + if (executableMemory[pte] != null) + return executableMemory[pte]; + + return null; + } + + @Override + public void changeProtection(int address, int len, boolean newRead, boolean newWrite, boolean newExec) { + + while (len > 0) { + int pte = getPTE(address); + int[] page = getPage(pte); + + if (page == null) + throw new SegmentationFault(address); + + readableMemory[pte] = newRead ? page : null; + writableMemory[pte] = newWrite ? page : null; + executableMemory[pte] = newExec ? page : null; + + address += PAGE_SIZE; + len -= PAGE_SIZE; + } + } + + /** + * Read an int from RandomAccessFile ensuring that a byte swap isn't performed + * + * @param file + * file to read from + * @return native endian read int + */ + protected int readInt(RandomAccessFile file) throws java.io.IOException { + + return file.readByte() << 24 | (file.readUnsignedByte() << 16) + | (file.readUnsignedByte() << 8) | (file.readUnsignedByte()); + } + + /** + * Map a page of memory from file + * + * @param file + * the file map in from + * @param addr + * the address to map or NULL if don't care + * @param len + * the amount of memory to map + * @param read + * is the page readable + * @param write + * is the page writable + * @param exec + * is the page executable + */ + public final int map(RandomAccessFile file, long offset, int addr, int len, + boolean read, boolean write, boolean exec) throws MemoryMapException { + // Check address is page aligned + if ((addr % PAGE_SIZE) != 0) { + MemoryMapException.unalignedAddress(addr); + } + // Check file offset is page aligned + /*if ((offset % PAGE_SIZE) != 0) { + MemoryMapException.unalignedFileOffset(offset); + }*/ + + if (DBT_Options.debugRuntime) { + System.out.println("Mapping file " + file + " offset=" + offset + + " addr=0x" + Integer.toHexString(addr) + " len=" + len + + (read ? " r" : " -") + (write ? "w" : "-") + (exec ? "x" : "-")); + } + addr = map(addr, len, read, write, exec); + + try { + file.seek(offset); + for (int i = 0; i < len; i += 4) { + + int[] page = getPage(getPTE(addr + i)); + page[getOffset(addr + i)] = readInt(file); + } + + return addr; + + } + catch (java.io.IOException e) { + throw new Error(e); + } + } + + /** + * Unmap a page of memory + * + * @param addr + * the address to unmap + * @param len + * the amount of memory to unmap + */ + public final void unmap(int addr, int len) { + for (int i = 0; i < len; i += PAGE_SIZE) { + + int pte = getPTE(addr + i); + + if (getPage(pte) != null) { + readableMemory[pte] = null; + writableMemory[pte] = null; + executableMemory[pte] = null; + } + else { + throw new Error("Unmapping memory that's not mapped addr=0x" + + Integer.toHexString(addr) + " len=" + len); + } + } + } + + /** + * Perform a 32bit load where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAligned32(int addr) { + return readableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a 32bit load where addr is word aligned and executable + * + * @param addr + * the address of the value to load + * @return the result + */ + protected final int loadWordAlignedInstruction32(int addr) { + return executableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned8(int addr) { + return (loadWordAligned32(addr) << ((addr & 0x3) << 3)) >> 24; + // switch(addr & 3) { + // default: + // return (loadWordAligned32(addr) << 24) >> 24; + // case 1: + // return (loadWordAligned32(addr) << 16) >> 24; + // case 2: + // return (loadWordAligned32(addr) << 8) >> 24; + // case 3: + // return loadWordAligned32(addr) >> 24; + // } + } + + /** + * Perform a byte load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned8(int addr) { + return (loadWordAligned32(addr) >> ((3 - (addr & 3)) << 3)) & 0xFF; + // switch(addr & 3) { + // default: + // return loadWordAligned32(addr) & 0xFF; + // case 1: + // return (loadWordAligned32(addr) >> 8) & 0xFF; + // case 2: + // return (loadWordAligned32(addr) >> 16) & 0xFF; + // case 3: + // return loadWordAligned32(addr) >>> 24; + // } + } + + /** + * Perform a 16bit load where the sign extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the sign extended result + */ + public int loadSigned16(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr) >> 16; + case 1: + return (loadWordAligned32(addr) << 8) >> 16; + case 2: + return (loadWordAligned32(addr) << 16) >> 16; + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr) << 24) >> 16) + | (loadWordAligned32(addr + 1) >>> 24); + } + } + + /** + * Perform a 16bit load where the zero extended result fills the return value + * + * @param addr + * the address of the value to load + * @return the zero extended result + */ + public int loadUnsigned16(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr) >>> 16; + case 1: + return (loadWordAligned32(addr) >> 8) & 0xFFFF; + case 2: + return loadWordAligned32(addr) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAligned32(addr) << 8) & 0xFF00) + | loadWordAligned32(addr + 1) >>> 24; + } + } + + /** + * Perform a 32bit load + * + * @param addr + * the address of the value to load + * @return the result + */ + public int load32(int addr) { + switch (addr & 3) { + default: + return loadWordAligned32(addr); + case 1: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr + 3) >>> 24) + | (loadWordAligned32(addr) << 8); + case 2: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr + 2) >>> 16) + | (loadWordAligned32(addr) << 16); + case 3: // 2 loads to deal with spanning int problem + return (loadWordAligned32(addr + 1) >>> 8) + | (loadWordAligned32(addr) << 24); + } + } + + /** + * Perform a 8bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction8(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) >>> 24; + case 1: + return (loadWordAlignedInstruction32(addr) >> 16) & 0xFF; + case 2: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFF; + case 3: + return loadWordAlignedInstruction32(addr) & 0xFF; + } + } + + @Override + public int loadInstruction16(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr) >>> 16; + case 1: + return (loadWordAlignedInstruction32(addr) >> 8) & 0xFFFF; + case 2: + return loadWordAlignedInstruction32(addr) & 0xFFFF; + case 3: // 2 loads to deal with spanning int problem + return ((loadWordAlignedInstruction32(addr) << 8) & 0xFF00) + | (loadWordAlignedInstruction32(addr + 1) >>> 25); + } + } + + /** + * Perform a 32bit load from memory that must be executable + * + * @param addr + * the address of the value to load + * @return the result + */ + public int loadInstruction32(int addr) { + switch (addr & 3) { + default: + return loadWordAlignedInstruction32(addr); + case 1: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr + 3) >>> 24) + | (loadWordAlignedInstruction32(addr) << 8); + case 2: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr + 2) >>> 16) + | (loadWordAlignedInstruction32(addr) << 16); + case 3: // 2 loads to deal with spanning int problem + return (loadWordAlignedInstruction32(addr + 1) >>> 8) + | (loadWordAlignedInstruction32(addr) << 24); + } + } + + /** + * Perform a 32bit aligned store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + final protected void storeWordAligned32(int addr, int value) { + writableMemory[getPTE(addr)][getOffset(addr)] = value; + } + + /** + * Perform a 32bit load, from writable memory, where addr is word aligned + * + * @param addr + * the address of the value to load + * @return the result + */ + final protected int loadWordAligned32forWrite(int addr) { + return writableMemory[getPTE(addr)][getOffset(addr)]; + } + + /** + * Perform a byte store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store8(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x00FFFFFF) + | (value << 24)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF00FFFF) + | ((value & 0xFF) << 16)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF00FF) + | ((value & 0xFF) << 8)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | (value & 0xFF)); + break; + } + } + + /** + * Perform a 16bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store16(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0x0000FFFF) + | (value << 16)); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF0000FF) + | ((value & 0xFFFF) << 8)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF0000) + | (value & 0xFFFF)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | ((value >> 8) & 0xFF)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0x00FFFFFF) + | (value << 24)); + break; + } + } + + /** + * Perform a 32bit store + * + * @param value + * the value to store + * @param addr + * the address of where to store + */ + public void store32(int addr, int value) { + switch (addr & 3) { + default: + storeWordAligned32(addr, value); + break; + case 1: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFF000000) + | (value >>> 8)); + storeWordAligned32(addr + 3, + (loadWordAligned32forWrite(addr + 3) & 0x00FFFFFF) | (value << 24)); + break; + case 2: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFF0000) + | (value >>> 16)); + storeWordAligned32(addr + 2, + (loadWordAligned32forWrite(addr + 2) & 0x0000FFFF) | (value << 16)); + break; + case 3: + storeWordAligned32(addr, (loadWordAligned32forWrite(addr) & 0xFFFFFF00) + | (value >>> 24)); + storeWordAligned32(addr + 1, + (loadWordAligned32forWrite(addr + 1) & 0x000000FF) | (value << 8)); + break; + } + } +} Modified: src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java =================================================================== --- src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/generic/memory/IntAddressedLittleEndianMemory.java 2007-08-27 15:14:38 UTC (rev 174) @@ -13,7 +13,6 @@ import org.binarytranslator.DBT; import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.fault.SegmentationFault; -import org.jikesrvm.VM_Configuration; import org.vmmagic.pragma.Inline; /** @@ -283,12 +282,8 @@ * @return native endian read int */ protected int readInt(RandomAccessFile file) throws java.io.IOException { - if (VM_Configuration.BuildForPowerPC) { - return file.readInt(); // NB this will always read in big-endian format - } else { - return file.readUnsignedByte() | (file.readUnsignedByte() << 8) - | (file.readUnsignedByte() << 16) | (file.readByte() << 24); - } + return file.readUnsignedByte() | (file.readUnsignedByte() << 8) + | (file.readUnsignedByte() << 16) | (file.readByte() << 24); } /** Modified: src/org/binarytranslator/generic/os/loader/elf/ELF_File.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_File.java 2007-08-27 15:14:38 UTC (rev 174) @@ -22,7 +22,23 @@ import org.binarytranslator.generic.os.process.ProcessSpace; public class ELF_File { + + /** Represents accepted ELF byte orders. */ + public enum ByteOrder implements IdentifiedEnum { + LittleEndian(1), + BigEndian(2); + + private int identifier; + + private ByteOrder(int identifier) { + this.identifier = identifier; + } + public int getIdentifier() { + return identifier; + } + } + /** Wrapper class used for reading the ELF file with the required endianness */ private BinaryReader reader; @@ -31,6 +47,10 @@ /** Program segment headers */ private SegmentHeader segmentHeaders[]; + + public ByteOrder getByteOrder() { + return header.byteOrder; + } /** * Debug information @@ -60,9 +80,9 @@ * @return * An ELF_BinaryReader, that hides the details of the byte order. */ - public static BinaryReader create(ELF_Identity.ByteOrder byteOrder, RandomAccessFile file) { + public static BinaryReader create(ByteOrder byteOrder, RandomAccessFile file) { - if (byteOrder == ELF_Identity.ByteOrder.BigEndian) + if (byteOrder == ByteOrder.BigEndian) return new NonSwappingReader(file); else return new ByteSwappingReader(file); @@ -296,22 +316,6 @@ } } - /** Represents accepted ELF byte orders. */ - private enum ByteOrder implements IdentifiedEnum { - LittleEndian(1), - BigEndian(2); - - private int identifier; - - private ByteOrder(int identifier) { - this.identifier = identifier; - } - - public int getIdentifier() { - return identifier; - } - } - /* Symbolic names for the most widely used ABIs. This is not an enum, because the list isn't complete. */ private static final byte ELFOSABI_SYSTEMV = 0; private static final byte ELFOSABI_HPUX = 1; @@ -334,13 +338,13 @@ private static final byte ELF_MAGIC_VALUE[] = { 0x7f, 'E', 'L','F' }; /** Specifies the size of an address within this elf.*/ - private AddressSize addressSize; + AddressSize addressSize; /** The byte order used by this elf.*/ - private ByteOrder byteOrder; + ByteOrder byteOrder; /** The ABI that is used by this ELF.*/ - private byte abi; + byte abi; /** * Construct/read ELF identity Modified: src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java =================================================================== --- src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-08-24 17:51:46 UTC (rev 173) +++ src/org/binarytranslator/generic/os/loader/elf/ELF_Loader.java 2007-08-27 15:14:38 UTC (rev 174) @@ -1,7 +1,6 @@ package org.binarytranslator.generic.os.loader.elf; import java.io.IOException; - import org.binarytranslator.DBT_Options; import org.binarytranslator.generic.os.loader.Loader; import org.binarytranslator.generic.os.process.ProcessSpace; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |