Commit d32e8016 authored by Lukáš Marek's avatar Lukáš Marek

reverted back to version 702

parent 0234a123
......@@ -3,6 +3,7 @@
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="src-re-disp"/>
<classpathentry kind="src" path="src-re-server"/>
<classpathentry kind="src" path="src-agent-java"/>
<classpathentry kind="src" path="src-test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="lib/asm-debug-all-4.0.jar"/>
......
......@@ -2,16 +2,19 @@ asm.lib=asm-debug-all-4.0.jar
asm.path=lib/${asm.lib}
src.disl=src
src.agent=src-agent
src.dynbypass=src-dynbypass
src.reagent=src-re-agent
src.redispatch=src-re-disp
src.dynbypass.act=src-dynbypass-act
src.agent.java=src-agent-java
src.agent.c=src-agent-c
src.reserver=src-re-server
src.redispatch=src-re-disp
src.reagent=src-re-agent
src.test=src-test
bin=bin
build=build
build.thread=build-thread
build.afterbootstrap=build-abs
extendedthread.path=${build}/extendedthread.jar
......
......@@ -41,10 +41,14 @@
</javac>
</target>
<target name="compile-agent">
<exec executable="make" dir="${src.agent}">
<arg value="whole" />
</exec>
<target name="compile-agent-java" depends="compile-dynamicbypass">
<javac srcdir="${src.agent.java}" destdir="${bin}" debug="true" includeAntRuntime="false">
<classpath refid="buildpath" />
</javac>
</target>
<target name="compile-agent-c">
<exec executable="make" dir="${src.agent.c}" />
</target>
<target name="compile-reserver">
......@@ -69,7 +73,7 @@
</javac>
</target>
<target name="compile" depends="compile-disl,compile-agent,compile-test,compile-reserver,compile-reagent,compile-redispatch" />
<target name="compile" depends="compile-disl,compile-agent-java,compile-agent-c,compile-test,compile-reserver,compile-redispatch" />
<target name="package-dislserver" depends="compile-disl">
<jar basedir="${bin}" destfile="${build}/disl-server.jar"
......@@ -84,6 +88,36 @@
</jar>
</target>
<target name="compile-dynamicbypass-afterbootstrap">
<mkdir dir="${build.afterbootstrap}" />
<javac srcdir="${src.dynbypass.act}" destdir="${build.afterbootstrap}" debug="true" includeAntRuntime="false">
<classpath refid="buildpath" />
</javac>
</target>
<target name="package-dislagent-java" depends="compile-agent-java,compile-dynamicbypass,compile-dynamicbypass-afterbootstrap">
<!-- rename after bootstrap class -->
<move file="${build.afterbootstrap}/ch/usi/dag/disl/dynamicbypass/DynamicBypassCheck.class"
tofile="${build.afterbootstrap}/DynamicBypassCheck-AfterBootstrap.class" />
<jar basedir="${bin}" destfile="${build}/disl-agent.jar"
includes="ch/usi/dag/dislagent/**,ch/usi/dag/disl/dynamicbypass/**">
<manifest>
<attribute name="Premain-Class" value="ch.usi.dag.dislagent.DiSLAgent" />
<attribute name="Can-Redefine-Classes" value="true" />
<attribute name="DiSL-Version" value="${disl.version}" />
</manifest>
<!-- include after bootstrap class -->
<fileset file="${build.afterbootstrap}/DynamicBypassCheck-AfterBootstrap.class" />
</jar>
<!-- delete dir with after bootstrap class -->
<delete dir="${build.afterbootstrap}" />
</target>
<target name="package-reserver" depends="compile-reserver">
<jar basedir="${bin}" destfile="${build}/dislre-server.jar"
includes="ch/usi/dag/dislreserver/**">
......@@ -101,15 +135,7 @@
</jar>
</target>
<target name="package-dynamicbypass" depends="compile-dynamicbypass">
<jar basedir="${bin}" destfile="${build}/disl-bypass.jar" includes="ch/usi/dag/disl/dynamicbypass/**">
<manifest>
<attribute name="DiSL-Version" value="${disl.version}" />
</manifest>
</jar>
</target>
<target name="package" depends="package-dislserver,package-dynamicbypass,package-reserver,package-redispatch,compile-agent,compile-reagent" />
<target name="package" depends="package-dislserver,package-dislagent-java,package-reserver,package-redispatch,compile-agent-c,compile-reagent" />
<target name="eclipse-agent" description="creates simple agent jar file for eclipse">
<mkdir dir="build" />
......@@ -139,7 +165,8 @@
<delete dir="${bin}" />
<delete dir="${build}" />
<delete dir="${build.thread}" />
<exec executable="make" dir="${src.agent}">
<delete dir="${build.afterbootstrap}" />
<exec executable="make" dir="${src.agent.c}">
<arg value="clean" />
</exec>
<exec executable="make" dir="${src.reagent}">
......
......@@ -14,10 +14,10 @@ fi
# determine libs depending on the OS
OS=`uname`
if [ "${OS}" = "Darwin" ]; then
AGENT="${DISL_LIB_P}/libdislagent.jnilib"
C_AGENT="${DISL_LIB_P}/libdislagent.jnilib"
RE_AGENT="${DISL_LIB_P}/libdislreagent.jnilib"
else
AGENT="${DISL_LIB_P}/libdislagent.so"
C_AGENT="${DISL_LIB_P}/libdislagent.so"
RE_AGENT="${DISL_LIB_P}/libdislreagent.so"
fi
......@@ -26,13 +26,8 @@ INSTR_LIB=$1
shift
# start the client
# options available:
# -Ddisl.bypass=never \
# -Ddisl.bypass=bootstrap \
# -Ddisl.bypass=dynamic \
# -Ddisl.splitmethods=false \
# -Ddisl.excepthandler=true \
${JAVA_HOME:+$JAVA_HOME/jre/bin/}java \
-agentpath:${AGENT} -agentpath:${RE_AGENT} \
-Xbootclasspath/a:${DISL_LIB_P}/disl-bypass.jar:${INSTR_LIB}:${DISL_LIB_P}/dislre-dispatch.jar \
-agentpath:${C_AGENT} -agentpath:${RE_AGENT} \
-javaagent:${DISL_LIB_P}/disl-agent.jar \
-Xbootclasspath/a:${DISL_LIB_P}/disl-agent.jar:${INSTR_LIB}:${DISL_LIB_P}/dislre-dispatch.jar \
"$@"
......@@ -7,22 +7,15 @@ BUILDDIR=../build
# Source lists
LIBNAME=dislagent
SOURCES=bytecode.c common.c jvmtiutil.c connection.c \
connpool.c msgchannel.c network.c dislagent.c
HEADERS=$(wildcard *.h) codeflags.h
SOURCES=dislagent.c
# Object files needed to create library
OBJECTS=$(SOURCES:%.c=%.o)
# Library name and options needed to build it
UNAME := $(shell uname)
ifeq ($(UNAME), Linux)
LIBRARY=lib$(LIBNAME).so
endif
ifeq ($(UNAME), Darwin)
LIBRARY=lib$(LIBNAME).jnilib
endif
......@@ -32,55 +25,31 @@ endif
LINK_SHARED=$(LINK.c) -shared -o $@
# GNU Compiler options needed to build it
COMMON_FLAGS=-fPIC -std=gnu99
COMMON_FLAGS=-fPIC
# Options that help find errors
COMMON_FLAGS+= -W -Wall -Wextra -Wno-unused-parameter -lpthread
COMMON_FLAGS+= -W -Wall -Wextra -O3 -Wno-unused-parameter
CFLAGS += $(COMMON_FLAGS)
CFLAGS += -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
# add debugging output
ifneq ($(DEBUG),)
CFLAGS += -DDEBUG -g
else
CFLAGS += -DNDEBUG -O3
ifeq ($(DEBUG), TRUE)
CFLAGS += -DDEBUG
endif
build: $(LIBRARY)
cp $(LIBRARY) $(BUILDDIR)
# Build native library
ifneq ($(WHOLE),)
$(LIBRARY): $(HEADERS) $(SOURCES)
gcc $(CFLAGS) -DWHOLE -fwhole-program -flto -shared -o $@ $(SOURCES)
else
$(LIBRARY): $(HEADERS) $(OBJECTS)
$(LIBRARY): $(OBJECTS)
$(LINK_SHARED) $(OBJECTS) $(LIBRARIES)
endif
BPC_CLASSES := $(wildcard bypass/*/*.class)
bytecode.c: $(BPC_CLASSES) bin2class
./bin2class \
$(foreach BPC,$(BPC_CLASSES),$(BPC) $(subst bypass/,bpc_,$(BPC:/BypassCheck.class=))) \
> $@
codeflags.h: codeflags
./codeflags
# Cleanup the built bits
clean:
rm -f $(LIBRARY) $(OBJECTS)
debug:
$(MAKE) DEBUG=1
whole:
$(MAKE) WHOLE=1
$(MAKE) DEBUG=TRUE
all: build
all: build
\ No newline at end of file
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include <jvmti.h>
#include <jni.h>
// has to be defined for jvmtihelper.h
#define ERR_PREFIX "DiSL agent error: "
#include "jvmtihelper.h"
#include "comm.h"
#include "dislagent.h"
static const int ERR_SERVER = 10003;
// defaults - be sure that space in host_name is long enough
static const char * DEFAULT_HOST = "localhost";
static const char * DEFAULT_PORT = "11217";
typedef struct {
jint control_size;
jint classcode_size;
const unsigned char * control;
const unsigned char * classcode;
} message;
// linked list to hold socket file descriptor
// access must be protected by monitor
struct strc_connection_item {
int sockfd;
volatile int available;
struct strc_connection_item *next;
};
typedef struct strc_connection_item connection_item;
// port and name of the instrumentation server
static char host_name[1024];
static char port_number[6]; // including final 0
static jvmtiEnv * jvmti_env;
static jrawMonitorID global_lock;
// we are using multiple connections for parallelization
// pros: there is no need for synchronization in this client :)
// cons: gets ugly with strong parallelization
// the first element on the list of connections
// modifications should be protected by critical section
static connection_item * conn_list = NULL;
// ******************* Helper routines *******************
static message create_message(const unsigned char * control,
jint control_size, const unsigned char * classcode,
jint classcode_size) {
message result;
// control + size
result.control_size = control_size;
// contract: (if control_size <= 0) pointer may be copied (stolen)
if(control != NULL && control_size > 0) {
// without ending 0
unsigned char * buffcn = (unsigned char *) malloc(control_size);
memcpy(buffcn, control, control_size);
result.control = buffcn;
}
else {
result.control = control;
result.control_size = abs(control_size);
}
// class code + size
result.classcode_size = classcode_size;
// contract: (if classcode_size <= 0) pointer may be copied (stolen)
if(classcode != NULL && classcode_size > 0) {
unsigned char * buffcc = (unsigned char *) malloc(classcode_size);
memcpy(buffcc, classcode, classcode_size);
result.classcode = buffcc;
}
else {
result.classcode = classcode;
result.classcode_size = abs(classcode_size);
}
return result;
}
static void free_message(message * msg) {
if(msg->control != NULL) {
// cast because of const
free((void *) msg->control);
msg->control = NULL;
msg->control_size = 0;
}
if(msg->classcode != NULL) {
// cast because of const
free((void *) msg->classcode);
msg->classcode = NULL;
msg->classcode_size = 0;
}
}
static void parse_agent_options(char *options) {
static const char PORT_DELIM = ':';
// assign defaults
strcpy(host_name, DEFAULT_HOST);
strcpy(port_number, DEFAULT_PORT);
// no options found
if (options == NULL) {
return;
}
char * port_start = strchr(options, PORT_DELIM);
// process port number
if(port_start != NULL) {
// replace PORT_DELIM with end of the string (0)
port_start[0] = '\0';
// move one char forward to locate port number
++port_start;
// convert number
int fitsP = strlen(port_start) < sizeof(port_number);
check_error(! fitsP, "Port number is too long");
strcpy(port_number, port_start);
}
// check if host_name is big enough
int fitsH = strlen(options) < sizeof(host_name);
check_error(! fitsH, "Host name is too long");
strcpy(host_name, options);
}
// ******************* Communication routines *******************
// sends class over network
static void send_msg(connection_item * conn, message * msg) {
#ifdef DEBUG
printf("Sending - control: %d, code: %d ... ", msg->control_size, msg->classcode_size);
#endif
// send control and code size first and then data
int sockfd = conn->sockfd;
// convert to java representation
jint nctls = htonl(msg->control_size);
send_data(sockfd, &nctls, sizeof(jint));
// convert to java representation
jint nccs = htonl(msg->classcode_size);
send_data(sockfd, &nccs, sizeof(jint));
send_data(sockfd, msg->control, msg->control_size);
send_data(sockfd, msg->classcode, msg->classcode_size);
#ifdef DEBUG
printf("done\n");
#endif
}
// receives class from network
static message rcv_msg(connection_item * conn) {
#ifdef DEBUG
printf("Receiving ");
#endif
// receive control and code size first and then data
int sockfd = conn->sockfd;
// *** receive control size - jint
jint nctls;
rcv_data(sockfd, &nctls, sizeof(jint));
// convert from java representation
jint control_size = ntohl(nctls);
// *** receive class code size - jint
jint nccs;
rcv_data(sockfd, &nccs, sizeof(jint));
// convert from java representation
jint classcode_size = ntohl(nccs);
// *** receive control string
// +1 - ending 0 - useful when printed - normally error msgs here
unsigned char * control = (unsigned char *) malloc(control_size + 1);
rcv_data(sockfd, control, control_size);
// terminate string
control[control_size] = '\0';
// *** receive class code
unsigned char * classcode = (unsigned char *) malloc(classcode_size);
rcv_data(sockfd, classcode, classcode_size);
#ifdef DEBUG
printf("- control: %d, code: %d ... done\n", control_size, classcode_size);
#endif
// negative length - create_message adopts pointers
return create_message(control, -control_size, classcode, -classcode_size);
}
static connection_item * open_connection() {
// get host address
struct addrinfo * addr;
int gai_res = getaddrinfo(host_name, port_number, NULL, &addr);
check_error(gai_res != 0, gai_strerror(gai_res));
// create stream socket
int sockfd = socket(addr->ai_family, SOCK_STREAM, 0);
check_std_error(sockfd, -1, "Cannot create socket");
// connect to server
int conn_res = connect(sockfd, addr->ai_addr, addr->ai_addrlen);
check_std_error(conn_res, -1, "Cannot connect to server");
// disable Nagle algorithm
// http://www.techrepublic.com/article/tcpip-options-for-high-performance-data-transmission/1050878
int flag = 1;
int set_res = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flag,
sizeof(int));
check_std_error(set_res, -1, "Cannot set TCP_NODELAY");
// free host address info
freeaddrinfo(addr);
// allocate new connection information
connection_item * conn = (connection_item *) malloc(sizeof(connection_item));
conn->available = TRUE;
conn->sockfd = sockfd;
conn->next = NULL;
return conn;
}
static void close_connection(connection_item * conn) {
// prepare close message - could be done more efficiently (this is nicer)
// close message has zeros as lengths
message close_msg = create_message(NULL, 0, NULL, 0);
// send close message
send_msg(conn, &close_msg);
// nothing was allocated but for completeness
free_message(&close_msg);
// close socket
close(conn->sockfd);
// free connection space
free(conn);
}
// get an available connection, create one if no one is available
static connection_item * acquire_connection() {
#ifdef DEBUG
printf("Acquiring connection ... ");
#endif
connection_item * curr;
// the connection list requires access using critical section
enter_critical_section(jvmti_env, global_lock);
{
curr = conn_list;
while (curr != NULL) {
if (curr->available == TRUE) {
break;
}
curr = curr->next;
}
if (curr == NULL) {
// create new connection
curr = open_connection();
// add it at the beginning of the connection list
curr->next = conn_list;
conn_list = curr;
}
curr->available = FALSE;
}
exit_critical_section(jvmti_env, global_lock);
#ifdef DEBUG
printf("done\n");
#endif
return curr;
}
// make the socket available again
static void release_connection(connection_item * conn) {
#ifdef DEBUG
printf("Releasing connection ... ");
#endif
// the connection list requires access using critical section
// BUT :), release can be done without it
//enter_critical_section(jvmti_env, global_lock);
{
// make connection available
conn->available = TRUE;
}
//exit_critical_section(jvmti_env, global_lock);
#ifdef DEBUG
printf("done\n");
#endif
}
// instruments remotely
static message instrument_class(const char * classname,
const unsigned char * classcode, jint classcode_size) {
// get available connection
connection_item * conn = acquire_connection();
// crate class data
message msg = create_message((const unsigned char *)classname,
strlen(classname), classcode, classcode_size);
send_msg(conn, &msg);
message result = rcv_msg(conn);