diff --git a/CHANGES.md b/CHANGES.md index 80c7613ea1..c21d491ccf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,7 @@ Features Bug Fixes --------- * [#925](https://github.com/java-native-access/jna/issues/925): Optimize `Structure#validate` and prevent `ArrayIndexOutOfBoundsException` in `SAFEARRAY#read` for zero dimensions - [@matthiasblaesing](https://github.com/matthiasblaesing). +* [#958](https://github.com/java-native-access/jna/issues/958): Update for PR 863: Old toolchains produce binaries without hard-/softfloat markers. Rasbian is missinng the markers and the oracle JDK is also affected. For hardfloat detection now also the Arm EABI section is also considered - [@matthiasblaesing](https://github.com/matthiasblaesing). Release 4.5.1 ============= diff --git a/ant-tools-src/com/sun/jna/BuildArmSoftFloatDetector.java b/ant-tools-src/com/sun/jna/BuildArmSoftFloatDetector.java index 6fa141dd15..fa851e9a7a 100644 --- a/ant-tools-src/com/sun/jna/BuildArmSoftFloatDetector.java +++ b/ant-tools-src/com/sun/jna/BuildArmSoftFloatDetector.java @@ -60,7 +60,7 @@ public void execute() throws IOException { // The self.getCanonicalPath() resolves the symblink to the backing // realfile and passes that to the detection routines ELFAnalyser ahfd = ELFAnalyser.analyse(self.getCanonicalPath()); - result = ahfd.isArmSoftFloat(); + result = ! ahfd.isArmHardFloat(); } catch (IOException ex) { result = false; } diff --git a/build.xml b/build.xml index f93e6c6bb9..d6b612e9a2 100644 --- a/build.xml +++ b/build.xml @@ -1015,11 +1015,17 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc + + + + + + diff --git a/native/Makefile b/native/Makefile index 6f9ad25bdc..059b999ea6 100644 --- a/native/Makefile +++ b/native/Makefile @@ -50,7 +50,7 @@ OS=$(shell uname | sed -e 's/CYGWIN.*/win32/g' \ -e 's/AIX.*/aix/g' \ -e 's/Linux.*/linux/g') -JNA_JNI_VERSION=5.1.0 # auto-generated by ant +JNA_JNI_VERSION=5.2.0 # auto-generated by ant CHECKSUM=74e8f8e397c43487738c5c1f1363498b # auto-generated by ant JAVA_INCLUDES=-I"$(JAVA_HOME)/include" \ diff --git a/src/com/sun/jna/ELFAnalyser.java b/src/com/sun/jna/ELFAnalyser.java index ba843821c7..85f4aceb2f 100644 --- a/src/com/sun/jna/ELFAnalyser.java +++ b/src/com/sun/jna/ELFAnalyser.java @@ -1,15 +1,25 @@ package com.sun.jna; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.RandomAccessFile; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; /** * Analyse an ELF file for platform specific attributes. - * + * *

Primary use-case: Detect whether the java binary is arm hardfloat or softfloat.

*/ class ELFAnalyser { @@ -30,19 +40,20 @@ class ELFAnalyser { private static final int EI_DATA_BIG_ENDIAN = 2; private static final int E_MACHINE_ARM = 0x28; private static final int EI_CLASS_64BIT = 2; - + public static ELFAnalyser analyse(String filename) throws IOException { ELFAnalyser res = new ELFAnalyser(filename); res.runDetection(); return res; } - + private final String filename; private boolean ELF = false; private boolean _64Bit = false; private boolean bigEndian = false; - private boolean armHardFloat = false; - private boolean armSoftFloat = false; + private boolean armHardFloatFlag = false; + private boolean armSoftFloatFlag = false; + private boolean armEabiAapcsVfp = false; private boolean arm = false; /** @@ -75,20 +86,32 @@ public String getFilename() { return filename; } + public boolean isArmHardFloat() { + return isArmEabiAapcsVfp() || isArmHardFloatFlag(); + } + + /** + * @return true if file was detected to specify, that FP parameters/result + * passing conforms to AAPCS, VFP variant (hardfloat) + */ + public boolean isArmEabiAapcsVfp() { + return armEabiAapcsVfp; + } + /** * @return true if file was detected to conform to the hardware floating-point - * procedure-call standard + * procedure-call standard via ELF flags */ - public boolean isArmHardFloat() { - return armHardFloat; + public boolean isArmHardFloatFlag() { + return armHardFloatFlag; } /** * @return true if file was detected to conform to the software floating-point - * procedure-call standard + * procedure-call standard via ELF flags */ - public boolean isArmSoftFloat() { - return armSoftFloat; + public boolean isArmSoftFloatFlag() { + return armSoftFloatFlag; } /** @@ -123,26 +146,423 @@ private void runDetection() throws IOException { // The total header size depends on the pointer size of the platform // so before the header is loaded the pointer size has to be determined byte sizeIndicator = raf.readByte(); + byte endianessIndicator = raf.readByte(); _64Bit = sizeIndicator == EI_CLASS_64BIT; + bigEndian = endianessIndicator == EI_DATA_BIG_ENDIAN; raf.seek(0); + // header length ByteBuffer headerData = ByteBuffer.allocate(_64Bit ? 64 : 52); raf.getChannel().read(headerData, 0); - bigEndian = headerData.get(5) == EI_DATA_BIG_ENDIAN; + headerData.order(bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + // e_machine arm = headerData.get(0x12) == E_MACHINE_ARM; if(arm) { + // e_flags int flags = headerData.getInt(_64Bit ? 0x30 : 0x24); - armHardFloat = (flags & EF_ARM_ABI_FLOAT_HARD) == EF_ARM_ABI_FLOAT_HARD; - armSoftFloat = !armHardFloat; + armHardFloatFlag = (flags & EF_ARM_ABI_FLOAT_HARD) == EF_ARM_ABI_FLOAT_HARD; + armSoftFloatFlag = (flags & EF_ARM_ABI_FLOAT_SOFT) == EF_ARM_ABI_FLOAT_SOFT; + + parseEabiAapcsVfp(headerData, raf); } } finally { try { raf.close(); } catch (IOException ex) { - // Swallow - closing + // Swallow - closing + } + } + } + + private void parseEabiAapcsVfp(ByteBuffer headerData, RandomAccessFile raf) throws IOException { + ELFSectionHeaders sectionHeaders = new ELFSectionHeaders(_64Bit, bigEndian, headerData, raf); + + for (ELFSectionHeaderEntry eshe : sectionHeaders.getEntries()) { + if(".ARM.attributes".equals(eshe.getName())) { + ByteBuffer armAttributesBuffer = ByteBuffer.allocate(eshe.getSize()); + armAttributesBuffer.order(bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + raf.getChannel().read(armAttributesBuffer, eshe.getOffset()); + armAttributesBuffer.rewind(); + Map> armAttributes = parseArmAttributes(armAttributesBuffer); + Map fileAttributes = armAttributes.get(1); + if(fileAttributes == null) { + continue; + } + /** + * Tag_ABI_VFP_args, (=28), uleb128 + * 0 The user intended FP parameter/result passing to conform to AAPCS, base variant + * 1 The user intended FP parameter/result passing to conform to AAPCS, VFP variant + * 2 The user intended FP parameter/result passing to conform to tool chain-specific conventions + * 3 Code is compatible with both the base and VFP variants; the non-variadic functions to pass FP parameters/results + */ + Object abiVFPargValue = fileAttributes.get(ArmAeabiAttributesTag.ABI_VFP_args); + if(abiVFPargValue instanceof Integer && ((Integer) abiVFPargValue).equals(1)) { + armEabiAapcsVfp = true; + } else if (abiVFPargValue instanceof BigInteger && ((BigInteger) abiVFPargValue).intValue() == 1) { + armEabiAapcsVfp = true; + } + } + } + } + + static class ELFSectionHeaders { + private final List entries = new ArrayList(); + + public ELFSectionHeaders(boolean _64bit, boolean bigEndian, ByteBuffer headerData, RandomAccessFile raf) throws IOException { + long shoff; + int shentsize; + int shnum; + short shstrndx; + if (_64bit) { + shoff = headerData.getLong(0x28); + shentsize = headerData.getShort(0x3A); + shnum = headerData.getShort(0x3C); + shstrndx = headerData.getShort(0x3E); + } else { + shoff = headerData.getInt(0x20); + shentsize = headerData.getShort(0x2E); + shnum = headerData.getShort(0x30); + shstrndx = headerData.getShort(0x32); + } + + int tableLength = shnum * shentsize; + + ByteBuffer data = ByteBuffer.allocate(tableLength); + data.order(bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + raf.getChannel().read(data, shoff); + + for(int i = 0; i < shnum; i++) { + data.position(i * shentsize); + ByteBuffer header = data.slice(); + header.order(data.order()); + header.limit(shentsize); + entries.add(new ELFSectionHeaderEntry(_64bit, header)); + } + + ELFSectionHeaderEntry stringTable = entries.get(shstrndx); + ByteBuffer stringBuffer = ByteBuffer.allocate(stringTable.getSize()); + stringBuffer.order(bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + raf.getChannel().read(stringBuffer, stringTable.getOffset()); + stringBuffer.rewind(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(20); + for (ELFSectionHeaderEntry eshe : entries) { + baos.reset(); + + ((Buffer) stringBuffer).position(eshe.getNameOffset()); + + while(stringBuffer.position() < stringBuffer.limit()) { + byte b = stringBuffer.get(); + if(b == 0) { + break; + } else { + baos.write(b); + } + } + + eshe.setName(baos.toString("ASCII")); + } + } + + public List getEntries() { + return entries; + } + } + + static class ELFSectionHeaderEntry { + private final int nameOffset; + private String name; + private final int type; + private final int flags; + private final int offset; + private final int size; + + public ELFSectionHeaderEntry(boolean _64bit, ByteBuffer sectionHeaderData) { + this.nameOffset = sectionHeaderData.getInt(0x0); + this.type = sectionHeaderData.getInt(0x4); + this.flags = (int) (_64bit ? sectionHeaderData.getLong(0x8) : sectionHeaderData.getInt(0x8)); + this.offset = (int) (_64bit ? sectionHeaderData.getLong(0x18) : sectionHeaderData.getInt(0x10)); + this.size = (int) (_64bit ? sectionHeaderData.getLong(0x20) : sectionHeaderData.getInt(0x14)); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getNameOffset() { + return nameOffset; + } + + public int getType() { + return type; + } + + public int getFlags() { + return flags; + } + + public int getOffset() { + return offset; + } + + public int getSize() { + return size; + } + + @Override + public String toString() { + return "ELFSectionHeaderEntry{" + "nameIdx=" + nameOffset + ", name=" + name + ", type=" + type + ", flags=" + flags + ", offset=" + offset + ", size=" + size + '}'; + } + } + + static class ArmAeabiAttributesTag { + + public enum ParameterType { + UINT32, NTBS, ULEB128 + } + + private final int value; + private final String name; + private final ParameterType parameterType; + + public ArmAeabiAttributesTag(int value, String name, ParameterType parameterType) { + this.value = value; + this.name = name; + this.parameterType = parameterType; + } + + public int getValue() { + return value; + } + + public String getName() { + return name; + } + + public ParameterType getParameterType() { + return parameterType; + } + + @Override + public String toString() { + return name + " (" + value + ")"; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 67 * hash + this.value; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ArmAeabiAttributesTag other = (ArmAeabiAttributesTag) obj; + if (this.value != other.value) { + return false; + } + return true; + } + + private static final List tags = new LinkedList(); + private static final Map valueMap = new HashMap(); + private static final Map nameMap = new HashMap(); + + // Enumerated from ARM IHI 0045E, 2.5 Attributes summary and history + public static final ArmAeabiAttributesTag File = addTag(1, "File", ParameterType.UINT32); + public static final ArmAeabiAttributesTag Section = addTag(2, "Section", ParameterType.UINT32); + public static final ArmAeabiAttributesTag Symbol = addTag(3, "Symbol", ParameterType.UINT32); + public static final ArmAeabiAttributesTag CPU_raw_name = addTag(4, "CPU_raw_name", ParameterType.NTBS); + public static final ArmAeabiAttributesTag CPU_name = addTag(5, "CPU_name", ParameterType.NTBS); + public static final ArmAeabiAttributesTag CPU_arch = addTag(6, "CPU_arch", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag CPU_arch_profile = addTag(7, "CPU_arch_profile", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ARM_ISA_use = addTag(8, "ARM_ISA_use", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag THUMB_ISA_use = addTag(9, "THUMB_ISA_use", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag FP_arch = addTag(10, "FP_arch", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag WMMX_arch = addTag(11, "WMMX_arch", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag Advanced_SIMD_arch = addTag(12, "Advanced_SIMD_arch", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag PCS_config = addTag(13, "PCS_config", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_PCS_R9_use = addTag(14, "ABI_PCS_R9_use", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_PCS_RW_data = addTag(15, "ABI_PCS_RW_data", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_PCS_RO_data = addTag(16, "ABI_PCS_RO_data", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_PCS_GOT_use = addTag(17, "ABI_PCS_GOT_use", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_PCS_wchar_t = addTag(18, "ABI_PCS_wchar_t", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_FP_rounding = addTag(19, "ABI_FP_rounding", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_FP_denormal = addTag(20, "ABI_FP_denormal", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_FP_exceptions = addTag(21, "ABI_FP_exceptions", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_FP_user_exceptions = addTag(22, "ABI_FP_user_exceptions", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_FP_number_model = addTag(23, "ABI_FP_number_model", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_align_needed = addTag(24, "ABI_align_needed", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_align8_preserved = addTag(25, "ABI_align8_preserved", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_enum_size = addTag(26, "ABI_enum_size", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_HardFP_use = addTag(27, "ABI_HardFP_use", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_VFP_args = addTag(28, "ABI_VFP_args", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_WMMX_args = addTag(29, "ABI_WMMX_args", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_optimization_goals = addTag(30, "ABI_optimization_goals", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_FP_optimization_goals = addTag(31, "ABI_FP_optimization_goals", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag compatibility = addTag(32, "compatibility", ParameterType.NTBS); + public static final ArmAeabiAttributesTag CPU_unaligned_access = addTag(34, "CPU_unaligned_access", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag FP_HP_extension = addTag(36, "FP_HP_extension", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag ABI_FP_16bit_format = addTag(38, "ABI_FP_16bit_format", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag MPextension_use = addTag(42, "MPextension_use", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag DIV_use = addTag(44, "DIV_use", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag nodefaults = addTag(64, "nodefaults", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag also_compatible_with = addTag(65, "also_compatible_with", ParameterType.NTBS); + public static final ArmAeabiAttributesTag conformance = addTag(67, "conformance", ParameterType.NTBS); + public static final ArmAeabiAttributesTag T2EE_use = addTag(66, "T2EE_use", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag Virtualization_use = addTag(68, "Virtualization_use", ParameterType.ULEB128); + public static final ArmAeabiAttributesTag MPextension_use2 = addTag(70, "MPextension_use", ParameterType.ULEB128); + + private static ArmAeabiAttributesTag addTag(int value, String name, ArmAeabiAttributesTag.ParameterType type) { + ArmAeabiAttributesTag tag = new ArmAeabiAttributesTag(value, name, type); + + if (!valueMap.containsKey(tag.getValue())) { + valueMap.put(tag.getValue(), tag); + } + if (!nameMap.containsKey(tag.getName())) { + nameMap.put(tag.getName(), tag); + } + tags.add(tag); + return tag; + } + + public static List getTags() { + return Collections.unmodifiableList(tags); + } + + public static ArmAeabiAttributesTag getByName(String name) { + return nameMap.get(name); + } + + public static ArmAeabiAttributesTag getByValue(int value) { + if (valueMap.containsKey(value)) { + return valueMap.get(value); + } else { + ArmAeabiAttributesTag pseudoTag = new ArmAeabiAttributesTag(value, "Unknown " + value, getParameterType(value)); + return pseudoTag; + } + } + + private static ArmAeabiAttributesTag.ParameterType getParameterType(int value) { + // ARM IHI 0045E, 2.2.6 Coding extensibility and compatibility + ArmAeabiAttributesTag tag = getByValue(value); + if (tag == null) { + if ((value % 2) == 0) { + return ArmAeabiAttributesTag.ParameterType.ULEB128; + } else { + return ArmAeabiAttributesTag.ParameterType.NTBS; + } + } else { + return tag.getParameterType(); + } + } + } + + + private static Map> parseArmAttributes(ByteBuffer bb) { + byte format = bb.get(); + if (format != 0x41) { + // Version A + // Not supported + return Collections.EMPTY_MAP; + } + while (bb.position() < bb.limit()) { + int posSectionStart = bb.position(); + int sectionLength = bb.getInt(); + if (sectionLength <= 0) { + // Fail! + break; + } + String vendorName = readNTBS(bb, null); + if ("aeabi".equals(vendorName)) { + return parseAEABI(bb); + } + ((Buffer) bb).position(posSectionStart + sectionLength); + } + return Collections.EMPTY_MAP; + } + + private static Map> parseAEABI(ByteBuffer buffer) { + Map> data = new HashMap>(); + while (buffer.position() < buffer.limit()) { + int pos = buffer.position(); + int subsectionTag = readULEB128(buffer).intValue(); + int length = buffer.getInt(); + if (subsectionTag == (byte) 1) { + data.put(subsectionTag, parseFileAttribute(buffer)); + } + ((Buffer) buffer).position(pos + length); + } + return data; + } + + private static Map parseFileAttribute(ByteBuffer bb) { + Map result = new HashMap(); + while (bb.position() < bb.limit()) { + int tagValue = readULEB128(bb).intValue(); + ArmAeabiAttributesTag tag = ArmAeabiAttributesTag.getByValue(tagValue); + switch (tag.getParameterType()) { + case UINT32: + result.put(tag, bb.getInt()); + break; + case NTBS: + result.put(tag, readNTBS(bb, null)); + break; + case ULEB128: + result.put(tag, readULEB128(bb)); + break; + } + } + return result; + } + + private static String readNTBS(ByteBuffer buffer, Integer position) { + if (position != null) { + ((Buffer) buffer).position(position); + } + int startingPos = buffer.position(); + byte currentByte; + do { + currentByte = buffer.get(); + } while (currentByte != '\0' && buffer.position() <= buffer.limit()); + int terminatingPosition = buffer.position(); + byte[] data = new byte[terminatingPosition - startingPos - 1]; + ((Buffer) buffer).position(startingPos); + buffer.get(data); + ((Buffer) buffer).position(buffer.position() + 1); + try { + return new String(data, "ASCII"); + } catch (UnsupportedEncodingException ex) { + throw new RuntimeException(ex); + } + } + + private static BigInteger readULEB128(ByteBuffer buffer) { + BigInteger result = BigInteger.ZERO; + int shift = 0; + while (true) { + byte b = buffer.get(); + result = result.or(BigInteger.valueOf(b & 127).shiftLeft(shift)); + if ((b & 128) == 0) { + break; } + shift += 7; } + return result; } } diff --git a/src/com/sun/jna/Platform.java b/src/com/sun/jna/Platform.java index 7a5a29c19b..7bd94799a7 100644 --- a/src/com/sun/jna/Platform.java +++ b/src/com/sun/jna/Platform.java @@ -268,7 +268,7 @@ static boolean isSoftFloat() { File self = new File("/proc/self/exe"); if (self.exists()) { ELFAnalyser ahfd = ELFAnalyser.analyse(self.getCanonicalPath()); - return ahfd.isArmSoftFloat(); + return ! ahfd.isArmHardFloat(); } } catch (IOException ex) { // asume hardfloat diff --git a/test/com/sun/jna/ELFAnalyserTest.java b/test/com/sun/jna/ELFAnalyserTest.java index fb65a21c92..29c47bbb27 100644 --- a/test/com/sun/jna/ELFAnalyserTest.java +++ b/test/com/sun/jna/ELFAnalyserTest.java @@ -2,8 +2,6 @@ package com.sun.jna; import java.io.*; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import org.junit.AfterClass; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -12,36 +10,33 @@ public class ELFAnalyserTest { - + private static final File TEST_RESOURCES = new File("build/test-resources"); private static final File WIN32_LIB = new File(TEST_RESOURCES, "win32-x86-64.dll"); private static final File LINUX_ARMEL_LIB = new File(TEST_RESOURCES, "linux-armel.so"); private static final File LINUX_ARMEL_NOFLAG_LIG = new File(TEST_RESOURCES, "linux-armel-noflag.so"); + private static final File LINUX_ARMHF_NOFLAG_LIG = new File(TEST_RESOURCES, "linux-armhf-noflag.so"); private static final File LINUX_ARMHF_LIB = new File(TEST_RESOURCES, "linux-armhf.so"); private static final File LINUX_AMD64_LIB = new File(TEST_RESOURCES, "linux-amd64.so"); - + @BeforeClass public static void initClass() throws IOException { - File win32Zip = new File("dist/win32-x86-64.jar"); - File linuxArmelZip = new File("dist/linux-armel.jar"); - File linuxArmhfZip = new File("dist/linux-arm.jar"); - File linuxAmd64Zip = new File("dist/linux-x86-64.jar"); - TEST_RESOURCES.mkdirs(); - - extractFileFromZip(win32Zip, "jnidispatch.dll", WIN32_LIB); - extractFileFromZip(linuxArmelZip, "libjnidispatch.so", LINUX_ARMEL_LIB); - extractFileFromZip(linuxArmhfZip, "libjnidispatch.so", LINUX_ARMHF_LIB); - extractFileFromZip(linuxAmd64Zip, "libjnidispatch.so", LINUX_AMD64_LIB); - makeLinuxArmelNoflagLib(LINUX_ARMEL_LIB, LINUX_ARMEL_NOFLAG_LIG); + + extractTestFile(WIN32_LIB); + extractTestFile(LINUX_ARMEL_LIB); + extractTestFile(LINUX_ARMHF_LIB); + extractTestFile(LINUX_AMD64_LIB); + makeLinuxArmNoflagLib(LINUX_ARMEL_LIB, LINUX_ARMEL_NOFLAG_LIG); + makeLinuxArmNoflagLib(LINUX_ARMHF_LIB, LINUX_ARMHF_NOFLAG_LIG); } - + @Test public void testNonELF() throws IOException { ELFAnalyser ahfd = ELFAnalyser.analyse(WIN32_LIB.getAbsolutePath()); assertFalse(ahfd.isELF()); } - + @Test public void testNonArm() throws IOException { ELFAnalyser ahfd = ELFAnalyser.analyse(LINUX_AMD64_LIB.getAbsolutePath()); @@ -49,24 +44,28 @@ public void testNonArm() throws IOException { assertFalse(ahfd.isArm()); assertTrue(ahfd.is64Bit()); } - + @Test public void testArmhf() throws IOException { ELFAnalyser ahfd = ELFAnalyser.analyse(LINUX_ARMHF_LIB.getAbsolutePath()); assertTrue(ahfd.isELF()); assertTrue(ahfd.isArm()); assertFalse(ahfd.is64Bit()); - assertFalse(ahfd.isArmSoftFloat()); + assertFalse(ahfd.isArmSoftFloatFlag()); + assertTrue(ahfd.isArmHardFloatFlag()); + assertTrue(ahfd.isArmEabiAapcsVfp()); assertTrue(ahfd.isArmHardFloat()); } - + @Test public void testArmel() throws IOException { ELFAnalyser ahfd = ELFAnalyser.analyse(LINUX_ARMEL_LIB.getAbsolutePath()); assertTrue(ahfd.isELF()); assertTrue(ahfd.isArm()); assertFalse(ahfd.is64Bit()); - assertTrue(ahfd.isArmSoftFloat()); + assertTrue(ahfd.isArmSoftFloatFlag()); + assertFalse(ahfd.isArmHardFloatFlag()); + assertFalse(ahfd.isArmEabiAapcsVfp()); assertFalse(ahfd.isArmHardFloat()); } @@ -76,10 +75,24 @@ public void testArmelNoflag() throws IOException { assertTrue(ahfd.isELF()); assertTrue(ahfd.isArm()); assertFalse(ahfd.is64Bit()); - assertTrue(ahfd.isArmSoftFloat()); + assertFalse(ahfd.isArmSoftFloatFlag()); + assertFalse(ahfd.isArmHardFloatFlag()); + assertFalse(ahfd.isArmEabiAapcsVfp()); assertFalse(ahfd.isArmHardFloat()); } - + + @Test + public void testArmhfNoflag() throws IOException { + ELFAnalyser ahfd = ELFAnalyser.analyse(LINUX_ARMHF_NOFLAG_LIG.getAbsolutePath()); + assertTrue(ahfd.isELF()); + assertTrue(ahfd.isArm()); + assertFalse(ahfd.is64Bit()); + assertFalse(ahfd.isArmSoftFloatFlag()); + assertFalse(ahfd.isArmHardFloatFlag()); + assertTrue(ahfd.isArmEabiAapcsVfp()); + assertTrue(ahfd.isArmHardFloat()); + } + @AfterClass public static void afterClass() throws IOException { LINUX_AMD64_LIB.delete(); @@ -87,17 +100,14 @@ public static void afterClass() throws IOException { LINUX_ARMEL_LIB.delete(); WIN32_LIB.delete(); LINUX_ARMEL_NOFLAG_LIG.delete(); + LINUX_ARMHF_NOFLAG_LIG.delete(); TEST_RESOURCES.delete(); } - - private static void extractFileFromZip(File zipTarget, String zipEntryName, File outputFile) throws IOException { - ZipFile zip = new ZipFile(zipTarget); + + private static void extractTestFile(File outputFile) throws IOException { + String inputPath = "/com/sun/jna/data/" + outputFile.getName(); + InputStream is = ELFAnalyserTest.class.getResourceAsStream(inputPath); try { - ZipEntry entry = zip.getEntry(zipEntryName); - if(entry == null) { - throw new IOException("ZipEntry for name " + zipEntryName + " not found in " + zipTarget.getAbsolutePath()); - } - InputStream is = zip.getInputStream(entry); // Implicitly closed by closing ZipFile OutputStream os = new FileOutputStream(outputFile); try { copyStream(is, os); @@ -105,16 +115,16 @@ private static void extractFileFromZip(File zipTarget, String zipEntryName, File os.close(); } } finally { - zip.close(); + is.close(); } } // The e_flags for elf arm binaries begin at an offset of 0x24 bytes. // The procedure call standard is coded on the second byte. - private static void makeLinuxArmelNoflagLib(File sourceFile, File outputFile) throws IOException { + private static void makeLinuxArmNoflagLib(File sourceFile, File outputFile) throws IOException { final int POS_ABI_FLOAT_BIT = (byte) 0x25; copyFile(sourceFile, outputFile); - + RandomAccessFile out = new RandomAccessFile(outputFile, "rw"); out.seek(POS_ABI_FLOAT_BIT); @@ -122,7 +132,7 @@ private static void makeLinuxArmelNoflagLib(File sourceFile, File outputFile) th out.close(); } - + private static void copyFile(File sourceFile, File outputFile) throws IOException { InputStream inputStream = null; OutputStream outputStream = null; @@ -135,7 +145,7 @@ private static void copyFile(File sourceFile, File outputFile) throws IOExceptio closeSilently(outputStream); } } - + private static void copyStream(InputStream is, OutputStream os) throws IOException { int read; byte[] buffer = new byte[1024 * 1024]; @@ -143,7 +153,7 @@ private static void copyStream(InputStream is, OutputStream os) throws IOExcepti os.write(buffer, 0, read); } } - + private static void closeSilently(Closeable closeable) { if(closeable == null) { return; diff --git a/test/com/sun/jna/data/info.txt b/test/com/sun/jna/data/info.txt new file mode 100644 index 0000000000..daa5994770 --- /dev/null +++ b/test/com/sun/jna/data/info.txt @@ -0,0 +1,28 @@ +These binaries: + +- linux-armhf.so +- linux-armel.so +- linux-amd64.so +- win32-x86-64.dll + +are needed for the ELFAnalysesTest. They are builds of the native part of JNA. + +These files are dual-licensed under 2 alternative Open Source/Free licenses: +LGPL 2.1 or later and Apache License 2.0. (starting with JNA version 4.0.0). + +You can freely decide which license you want to apply to +the project. + +You may obtain a copy of the LGPL License at: + +http://www.gnu.org/licenses/licenses.html + +A copy is also included in the downloadable source code package +containing JNA, in file "LGPL2.1". + +You may obtain a copy of the Apache License at: + +http://www.apache.org/licenses/ + +A copy is also included in the downloadable source code package +containing JNA, in file "AL2.0". \ No newline at end of file diff --git a/test/com/sun/jna/data/linux-amd64.so b/test/com/sun/jna/data/linux-amd64.so new file mode 100644 index 0000000000..93db79e8e1 Binary files /dev/null and b/test/com/sun/jna/data/linux-amd64.so differ diff --git a/test/com/sun/jna/data/linux-armel.so b/test/com/sun/jna/data/linux-armel.so new file mode 100644 index 0000000000..a060034cb0 Binary files /dev/null and b/test/com/sun/jna/data/linux-armel.so differ diff --git a/test/com/sun/jna/data/linux-armhf.so b/test/com/sun/jna/data/linux-armhf.so new file mode 100644 index 0000000000..2a5dba660d Binary files /dev/null and b/test/com/sun/jna/data/linux-armhf.so differ diff --git a/test/com/sun/jna/data/win32-x86-64.dll b/test/com/sun/jna/data/win32-x86-64.dll new file mode 100644 index 0000000000..10d49b2d34 Binary files /dev/null and b/test/com/sun/jna/data/win32-x86-64.dll differ