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