Skip to content

Commit

Permalink
Add support for dlvsym(3)
Browse files Browse the repository at this point in the history
  • Loading branch information
smortex committed Mar 18, 2019
1 parent 37ac832 commit df28ea8
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 4 deletions.
23 changes: 23 additions & 0 deletions jni/jffi/Library.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ enum { RTLD_LAZY=1, RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL };
const char *e = dlerror(); snprintf(buf, size, "%s", e ? e : "unknown"); \
} while(0)
# define dl_sym(handle, name) dlsym(handle, name)
# define dl_vsym(handle, name, version) dlvsym(handle, name, version)
# define dl_close(handle) dlclose(handle)
#ifndef RTLD_LOCAL
# define RTLD_LOCAL 8
Expand Down Expand Up @@ -154,6 +155,28 @@ Java_com_kenai_jffi_Foreign_dlsym(JNIEnv* env, jclass cls, jlong handle, jstring
return p2j(addr);
}

JNIEXPORT jlong JNICALL
Java_com_kenai_jffi_Foreign_dlvsym(JNIEnv* env, jclass cls, jlong handle, jstring jsymbol, jstring jversion)
{
char sym[1024];
char version[1024];
void* addr;

getMultibyteString(env, sym, jsymbol, sizeof(sym));
getMultibyteString(env, version, jversion, sizeof(version));
#ifndef _WIN32
dlerror(); // clear any errors
#endif
addr = dl_vsym(j2p(handle), sym, version);
if (addr == NULL) {
char errbuf[1024] = { 0 };
dl_error(errbuf, sizeof(errbuf) - 1);
throwException(env, UnsatisfiedLink, "%s", errbuf);
}

return p2j(addr);
}

/*
* Class: com_kenai_jffi_Foreign
* Method: dlerror
Expand Down
8 changes: 4 additions & 4 deletions libtest/GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ JFLAGS = -fno-omit-frame-pointer -fno-strict-aliasing
OFLAGS = -O2 $(JFLAGS)
WFLAGS = -W -Werror -Wall -Wno-unused -Wno-unused-parameter -Wno-parentheses
PICFLAGS = -fPIC
SOFLAGS = -shared -Wl,-O1
SOFLAGS = -shared -Wl,-O1 -Wl,--version-script,$(SRC_DIR)/libtest.map
LDFLAGS += $(SOFLAGS)

IFLAGS = -I"$(BUILD_DIR)"
Expand Down Expand Up @@ -127,17 +127,17 @@ ifeq ($(OS), solaris)
CC = gcc
CFLAGS += -std=c99
LD = /usr/ccs/bin/ld
SOFLAGS = -shared -static-libgcc
SOFLAGS = -shared -static-libgcc -Wl,--version-script,$(SRC_DIR)/libtest.map
endif

ifeq ($(OS), aix)
LIBEXT = a
SOFLAGS = -shared -static-libgcc
SOFLAGS = -shared -static-libgcc -Wl,--version-script,$(SRC_DIR)/libtest.map
PICFLAGS += -pthread
endif

ifneq ($(findstring bsd, $(OS)),)
SOFLAGS = -shared -static-libgcc
SOFLAGS = -shared -static-libgcc -Wl,--version-script,$(SRC_DIR)/libtest.map
CFLAGS += -pthread
LDFLAGS += -pthread
endif
Expand Down
14 changes: 14 additions & 0 deletions libtest/VersionedSymbols.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
int
old_answer(void)
{
return 41;
}

int
new_answer(void)
{
return 42;
}

__asm__(".symver old_answer,answer@VERS_1.0");
__asm__(".symver new_answer,answer@@VERS_1.1");
2 changes: 2 additions & 0 deletions libtest/libtest.map
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VERS_1.0 {};
VERS_1.1 {};
10 changes: 10 additions & 0 deletions src/main/java/com/kenai/jffi/Foreign.java
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,16 @@ static boolean isMemoryProtectionEnabled() {
*/
static native long dlsym(long handle, String name);

/**
* Locates the memory address of the specified version of a dynamic library symbol.
*
* @param handle A dynamic library handle obtained from {@link #dlopen}
* @param name The name of the symbol.
* @param version The version of the symbol.
* @return The address where the symbol in loaded in memory.
*/
static native long dlvsym(long handle, String name, String version);

/**
* Gets the last error raised by {@link #dlopen} or {@link #dlsym}
*
Expand Down
17 changes: 17 additions & 0 deletions src/main/java/com/kenai/jffi/Library.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,23 @@ public final long getSymbolAddress(String name) {
}
}

/**
* Gets the address of a symbol within the <tt>Library</tt>.
*
* @param name The name of the symbol to locate.
* @param version The version of the symbol to locate.
* @return The address of the symbol within the current address space.
*/
public final long getSymbolAddressWithVersion(String name, String version) {
try {
return foreign.dlvsym(handle, name, version);

} catch (UnsatisfiedLinkError ex) {
lastError.set(foreign.dlerror());
return 0;
}
}

/**
* Gets the current error string from dlopen/LoadLibrary.
*
Expand Down
7 changes: 7 additions & 0 deletions src/test/java/com/kenai/jffi/UnitHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ public static Address findSymbol(String name) {
}
return new Address(address);
}
public static Address findSymbolWithVersion(String name, String version) {
final long address = LibraryHolder.libtest.getSymbolAddressWithVersion(name, version);
if (address == 0L) {
throw new UnsatisfiedLinkError("Could not locate symbol '" + name + "' at version '" + version + "'");
}
return new Address(address);
}
private static final class NativeInvocationHandler implements InvocationHandler {
private final ConcurrentMap<Method, MethodInvoker> invokers
= new ConcurrentHashMap<Method, MethodInvoker>();
Expand Down
44 changes: 44 additions & 0 deletions src/test/java/com/kenai/jffi/VersionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.kenai.jffi;

import org.junit.Test;

import com.kenai.jffi.InvokerTest.HeapInvoker;
import com.kenai.jffi.InvokerTest.NativeInvoker;
import com.kenai.jffi.UnitHelper.Address;

import static org.junit.Assert.assertEquals;

public class VersionTest {

public VersionTest() {
}

@Test public void old_answer() {
Invoker invoker = new NativeInvoker();

Address sym = UnitHelper.findSymbolWithVersion("answer", "VERS_1.0");
Function function = new Function(sym.address, Type.SINT);
CallContext ctx = new CallContext(Type.SINT);

long res = invoker.invokeN0(ctx, function.getFunctionAddress());

assertEquals(41, res);
}

@Test public void new_answer() {
Invoker invoker = new HeapInvoker();

Address sym = UnitHelper.findSymbolWithVersion("answer", "VERS_1.1");
Function function = new Function(sym.address, Type.SINT);
CallContext ctx = new CallContext(Type.SINT);

long res = invoker.invokeN0(ctx, function.getFunctionAddress());

assertEquals(42, res);
}

@Test(expected = UnsatisfiedLinkError.class)
public void future_answer() {
UnitHelper.findSymbolWithVersion("answer", "VERS_1.2");
}
}

0 comments on commit df28ea8

Please sign in to comment.