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

Merged trunk to remoteval branch revisions 477:484

parent 2e3231a8
#ifndef _COMM_H
#define _COMM_H
#include <sys/types.h>
#include <sys/socket.h>
#include "jvmtihelper.h"
// sends data over network
static void send_data(int sockfd, const void * data, int data_len) {
int sent = 0;
while (sent != data_len) {
int res = send(sockfd, ((unsigned char *)data) + sent,
(data_len - sent), 0);
check_std_error(res, -1, "Error while sending data to server");
sent += res;
}
}
// receives data from network
static void rcv_data(int sockfd, void * data, int data_len) {
int received = 0;
while (received != data_len) {
int res = recv(sockfd, ((unsigned char *)data) + received,
(data_len - received), 0);
check_std_error(res, -1, "Error while receiving data from server");
received += res;
}
}
#endif /* _COMM_H */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
......@@ -9,14 +8,16 @@
#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_JVMTI = 10001;
static const int ERR_COMM = 10002;
static const int ERR_SERVER = 10003;
static const char * ERR_PREFIX = "ERROR in DiSL agent: ";
static const int TRUE = 1;
static const int FALSE = 0;
......@@ -58,71 +59,6 @@ static connection_item * conn_list = NULL;
// ******************* Helper routines *******************
/*
* Check error routine - reporting on one place
*/
static void check_std_error(int retval, int errorval,
const char *str) {
if (retval == errorval) {
static const int BUFFSIZE = 1024;
char msgbuf[BUFFSIZE];
snprintf(msgbuf, BUFFSIZE, "%s%s", ERR_PREFIX, str);
perror(msgbuf);
exit(ERR_COMM);
}
}
/*
* Every JVMTI interface returns an error code, which should be checked
* to avoid any cascading errors down the line.
* The interface GetErrorName() returns the actual enumeration constant
* name, making the error messages much easier to understand.
*/
static void check_jvmti_error(jvmtiEnv *jvmti, jvmtiError errnum,
const char *str) {
if (errnum != JVMTI_ERROR_NONE) {
char *errnum_str;
errnum_str = NULL;
(void) (*jvmti)->GetErrorName(jvmti, errnum, &errnum_str);
fprintf(stderr, "%sJVMTI: %d(%s): %s\n", ERR_PREFIX, errnum,
(errnum_str == NULL ? "Unknown" : errnum_str),
(str == NULL ? "" : str));
exit(ERR_JVMTI);
}
}
/*
* Enter a critical section by doing a JVMTI Raw Monitor Enter
*/
static void enter_critical_section(jvmtiEnv *jvmti, jrawMonitorID lock_id) {
jvmtiError error;
error = (*jvmti)->RawMonitorEnter(jvmti, lock_id);
check_jvmti_error(jvmti, error, "Cannot enter with raw monitor");
}
/*
* Exit a critical section by doing a JVMTI Raw Monitor Exit
*/
static void exit_critical_section(jvmtiEnv *jvmti, jrawMonitorID lock_id) {
jvmtiError error;
error = (*jvmti)->RawMonitorExit(jvmti, lock_id);
check_jvmti_error(jvmti, error, "Cannot exit with raw monitor");
}
static message create_message(const unsigned char * control,
jint control_size, const unsigned char * classcode,
jint classcode_size) {
......@@ -224,35 +160,6 @@ static void parse_agent_options(char *options) {
// ******************* Communication routines *******************
// sends data over network
static void send_data(int sockfd, const void * data, int data_len) {
int sent = 0;
while (sent != data_len) {
int res = send(sockfd, ((unsigned char *)data) + sent,
(data_len - sent), 0);
check_std_error(res, -1, "Error while sending data to server");
sent += res;
}
}
// receives data from network
static void rcv_data(int sockfd, void * data, int data_len) {
int received = 0;
while (received != data_len) {
int res = recv(sockfd, ((unsigned char *)data) + received,
(data_len - received), 0);
check_std_error(res, -1, "Error while receiving data from server");
received += res;
}
}
// sends class over network
static void send_msg(connection_item * conn, message * msg) {
......@@ -580,9 +487,6 @@ JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
// class hook
cap.can_generate_all_class_hook_events = 1;
// timer
cap.can_get_current_thread_cpu_time = 1;
error = (*jvmti_env)->AddCapabilities(jvmti_env, &cap);
check_jvmti_error(jvmti_env, error,
"Unable to get necessary JVMTI capabilities.");
......@@ -601,7 +505,7 @@ JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
check_jvmti_error(jvmti_env, error, "Cannot set class load hook");
error = (*jvmti_env)->SetEventNotificationMode(jvmti_env, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
check_jvmti_error(jvmti_env, error, "Cannot create jvm death hook");
check_jvmti_error(jvmti_env, error, "Cannot set jvm death hook");
error = (*jvmti_env)->CreateRawMonitor(jvmti_env, "agent data", &global_lock);
check_jvmti_error(jvmti_env, error, "Cannot create raw monitor");
......
#include <jvmti.h>
#ifndef _DISLAGENT_H
#define _DISLAGENT_H
#include <jvmti.h>
#ifdef __cplusplus
extern "C" {
#endif
......@@ -13,5 +13,4 @@ JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved);
}
#endif
#endif /* _DISLAGENT_H */
#ifndef _JVMTIHELPER_H
#define _JVMTIHELPER_H
#ifndef ERR_PREFIX
#error ERR_PREFIX macro has to be deffined
#endif
#include <jvmti.h>
#include <stdlib.h>
static const int ERR_JVMTI = 10001;
static const int ERR_COMM = 10002;
/*
* Check error routine - reporting on one place
*/
static void check_std_error(int retval, int errorval,
const char *str) {
if (retval == errorval) {
static const int BUFFSIZE = 1024;
char msgbuf[BUFFSIZE];
snprintf(msgbuf, BUFFSIZE, "%s%s", ERR_PREFIX, str);
perror(msgbuf);
exit(ERR_COMM);
}
}
/*
* Every JVMTI interface returns an error code, which should be checked
* to avoid any cascading errors down the line.
* The interface GetErrorName() returns the actual enumeration constant
* name, making the error messages much easier to understand.
*/
static void check_jvmti_error(jvmtiEnv *jvmti, jvmtiError errnum,
const char *str) {
if (errnum != JVMTI_ERROR_NONE) {
char *errnum_str;
errnum_str = NULL;
(void) (*jvmti)->GetErrorName(jvmti, errnum, &errnum_str);
fprintf(stderr, "%sJVMTI: %d(%s): %s\n", ERR_PREFIX, errnum,
(errnum_str == NULL ? "Unknown" : errnum_str),
(str == NULL ? "" : str));
exit(ERR_JVMTI);
}
}
/*
* Enter a critical section by doing a JVMTI Raw Monitor Enter
*/
static void enter_critical_section(jvmtiEnv *jvmti, jrawMonitorID lock_id) {
jvmtiError error;
error = (*jvmti)->RawMonitorEnter(jvmti, lock_id);
check_jvmti_error(jvmti, error, "Cannot enter with raw monitor");
}
/*
* Exit a critical section by doing a JVMTI Raw Monitor Exit
*/
static void exit_critical_section(jvmtiEnv *jvmti, jrawMonitorID lock_id) {
jvmtiError error;
error = (*jvmti)->RawMonitorExit(jvmti, lock_id);
check_jvmti_error(jvmti, error, "Cannot exit with raw monitor");
}
#endif /* _JVMTIHELPER_H */
......@@ -77,82 +77,70 @@ public class DiSL {
private final List<Snippet> snippets;
// this method should be called only once
public DiSL(boolean useDynamicBypass) throws Exception {
public DiSL(boolean useDynamicBypass) throws DiSLException {
this.useDynamicBypass = useDynamicBypass;
// report DiSL exception within our code
try {
// *** resolve transformer ***
transformer = resolveTransformer();
// *** resolve transformer ***
transformer = resolveTransformer();
// transfomer output propagation
if(transformer == null) {
transPropagateUninstr = false;
}
else {
transPropagateUninstr =
transformer.propagateUninstrumentedClasses();
}
// transfomer output propagation
if (transformer == null) {
transPropagateUninstr = false;
} else {
transPropagateUninstr =
transformer.propagateUninstrumentedClasses();
}
// *** prepare exclusion set ***
exclusionSet = ExclusionSet.prepare();
// *** load disl classes ***
List<InputStream> dislClasses = ClassByteLoader.loadDiSLClasses();
if(dislClasses == null) {
throw new InitException("Cannot load DiSL classes. Please set" +
" the property " + ClassByteLoader.PROP_DISL_CLASSES
+ " or supply jar with DiSL classes"
+ " and proper manifest");
}
// *** prepare exclusion set ***
exclusionSet = ExclusionSet.prepare();
// *** parse disl classes ***
// - create snippets
// - create static context methods
// *** load disl classes ***
List<InputStream> dislClasses = ClassByteLoader.loadDiSLClasses();
ClassParser parser = new ClassParser();
if (dislClasses == null) {
throw new InitException("Cannot load DiSL classes. Please set"
+ " the property " + ClassByteLoader.PROP_DISL_CLASSES
+ " or supply jar with DiSL classes"
+ " and proper manifest");
}
for (InputStream classIS : dislClasses) {
parser.parse(classIS);
}
// *** parse disl classes ***
// - create snippets
// - create static context methods
// initialize processors
Map<Type, Proc> processors = parser.getProcessors();
for (Proc processor : processors.values()) {
processor.init(parser.getAllLocalVars());
}
ClassParser parser = new ClassParser();
List<Snippet> parsedSnippets = parser.getSnippets();
for (InputStream classIS : dislClasses) {
parser.parse(classIS);
}
// initialize snippets
for (Snippet snippet : parsedSnippets) {
snippet.init(parser.getAllLocalVars(), processors,
exceptHandler, useDynamicBypass);
}
// initialize snippets variable
// - this is set when everything is ok
// - it serves as initialization flag
snippets = parsedSnippets;
// TODO put checker here
// like After should catch normal and abnormal execution
// but if you are using After (AfterThrowing) with BasicBlockMarker
// or InstructionMarker that doesn't throw exception, then it is
// probably something, you don't want - so just warn the user
// also it can warn about unknown opcodes if you let user to
// specify this for InstructionMarker
}
catch (DiSLException e) {
reportError(e);
// initialize processors
Map<Type, Proc> processors = parser.getProcessors();
for (Proc processor : processors.values()) {
processor.init(parser.getAllLocalVars());
}
List<Snippet> parsedSnippets = parser.getSnippets();
// signal error
throw e;
// initialize snippets
for (Snippet snippet : parsedSnippets) {
snippet.init(parser.getAllLocalVars(), processors, exceptHandler,
useDynamicBypass);
}
// initialize snippets variable
// - this is set when everything is ok
// - it serves as initialization flag
snippets = parsedSnippets;
// TODO put checker here
// like After should catch normal and abnormal execution
// but if you are using After (AfterThrowing) with BasicBlockMarker
// or InstructionMarker that doesn't throw exception, then it is
// probably something, you don't want - so just warn the user
// also it can warn about unknown opcodes if you let user to
// specify this for InstructionMarker
}
private Transformer resolveTransformer() throws ManifestInfoException,
......@@ -193,21 +181,6 @@ public class DiSL {
}
}
private void reportError(DiSLException e) {
// error report for user (input) errors
System.err.println("DiSL error: " + e.getMessage());
Throwable cause = e.getCause();
while (cause != null) {
System.err.println(" Inner error: " + cause.getMessage());
cause = cause.getCause();
}
if(debug) {
e.printStackTrace();
}
}
/**
* Instruments a method in a class.
*
......@@ -380,77 +353,66 @@ public class DiSL {
}
// this method is thread safe after initialization
private InstrumentedClass instrument(ClassNode classNode)
private InstrumentedClass instrumentClass(ClassNode classNode)
throws DiSLException {
// report DiSL exception within our code
try {
// NOTE that class can be changed without changing any method
// - adding thread local fields
boolean classChanged = false;
// NOTE that class can be changed without changing any method
// - adding thread local fields
boolean classChanged = false;
// track changed methods for code merging
Set<String> changedMethods = new HashSet<String>();
// track changed methods for code merging
Set<String> changedMethods = new HashSet<String>();
// instrument all methods in a class
for (MethodNode methodNode : classNode.methods) {
// instrument all methods in a class
for (MethodNode methodNode : classNode.methods) {
boolean methodChanged = instrumentMethod(classNode, methodNode);
boolean methodChanged = instrumentMethod(classNode, methodNode);
// add method to the set of changed methods
if(methodChanged) {
changedMethods.add(methodNode.name + methodNode.desc);
classChanged = true;
}
// add method to the set of changed methods
if (methodChanged) {
changedMethods.add(methodNode.name + methodNode.desc);
classChanged = true;
}
// instrument thread local fields
if (Type.getInternalName(Thread.class).equals(classNode.name)) {
Set<ThreadLocalVar> insertTLVs = new HashSet<ThreadLocalVar>();
// dynamic bypass
if(useDynamicBypass) {
// prepare dynamic bypass thread local variable
ThreadLocalVar tlv = new ThreadLocalVar(null, "bypass",
Type.getType(boolean.class), false);
tlv.setDefaultValue(0);
insertTLVs.add(tlv);
}
// get all thread locals in snippets
for(Snippet snippet : snippets) {
insertTLVs.addAll(snippet.getCode().getReferencedTLVs());
}
}
if(! insertTLVs.isEmpty()) {
// instrument fields
ClassNode cnWithFields = new ClassNode(Opcodes.ASM4);
classNode.accept(new TLVInserter(cnWithFields, insertTLVs));
// replace original code with instrumented one
classNode = cnWithFields;
classChanged = true;
}
// instrument thread local fields
if (Type.getInternalName(Thread.class).equals(classNode.name)) {
Set<ThreadLocalVar> insertTLVs = new HashSet<ThreadLocalVar>();
// dynamic bypass
if (useDynamicBypass) {
// prepare dynamic bypass thread local variable
ThreadLocalVar tlv = new ThreadLocalVar(null, "bypass",
Type.getType(boolean.class), false);
tlv.setDefaultValue(0);
insertTLVs.add(tlv);
}
// we have changed some methods
if(classChanged) {
return new InstrumentedClass(classNode, changedMethods);
// get all thread locals in snippets
for (Snippet snippet : snippets) {
insertTLVs.addAll(snippet.getCode().getReferencedTLVs());
}
if (!insertTLVs.isEmpty()) {
// instrument fields
ClassNode cnWithFields = new ClassNode(Opcodes.ASM4);
classNode.accept(new TLVInserter(cnWithFields, insertTLVs));
// replace original code with instrumented one
classNode = cnWithFields;
classChanged = true;
}
return null;
}
catch (DiSLException e) {
reportError(e);
// signal error
throw e;
// we have changed some methods
if (classChanged) {
return new InstrumentedClass(classNode, changedMethods);
}
return null;
}
public byte[] instrument(byte[] classAsBytes) throws DiSLException {
......@@ -490,7 +452,7 @@ public class DiSL {
classReader.accept(classNode, ClassReader.SKIP_DEBUG
| ClassReader.EXPAND_FRAMES);
InstrumentedClass instrClass = instrument(classNode);
InstrumentedClass instrClass = instrumentClass(classNode);
if(instrClass == null) {
......
package ch.usi.dag.dislserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicInteger;
......@@ -58,16 +59,37 @@ public abstract class DiSLServer {
}
}
} catch (Exception e) {
}
catch (IOException e) {
reportError(new DiSLServerException(e));
}
catch (Throwable e) {
reportError(e);
}
}
private static void reportInnerError(Throwable e) {
Throwable cause = e.getCause();
while (cause != null && cause.getMessage() != null) {
System.err.println(" Inner error: " + cause.getMessage());
cause = cause.getCause();
}
}
public static void reportError(Throwable e) {
if (e instanceof DiSLException) {
// Error reported in DiSL - just exit
System.err.println("DiSL error: " + e.getMessage());
reportInnerError(e);
if(debug) {
e.printStackTrace();
}
return;
}
......@@ -75,13 +97,17 @@ public abstract class DiSLServer {
System.err.println("DiSL server error: " + e.getMessage());
reportInnerError(e);
if (debug) {
e.printStackTrace();
}
return;
}
// fatal exception (unexpected)
System.err.println("Fatal error: " + e.getMessage());
System.err.println("DiSL fatal error: " + e.getMessage());
e.printStackTrace();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment