Commit 9b4ceca9 authored by Lukáš Marek's avatar Lukáš Marek

Added simple README - needs more work

c-agent - some check_std_error replaced with check_error
first part of public API documentation
parent 7606d670
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>disl</name> <name>DiSL</name>
<comment></comment> <comment></comment>
<projects> <projects>
</projects> </projects>
......
The DiSL language is hosted in Java using annotations, therefore, no special compiler is required.
A convenient way to specify an instrumentation and to pass it to the DiSL framework is to pack the instrumentation classes with a manifest file into one jar.
The DiSL framework will load the jar, parse the instrumentation specification, and instrument all classes used by an application at load-time.
The examples of simple instrumentation are in src-test directory.
The test can be invoked using runTest.sh script in the root directory.
For user defined instrumentation, it is recommended to mimic the start and build script as they are provided for test.
We are working on better setup scripts to ease the setup effort for developer.
...@@ -8,8 +8,6 @@ else ...@@ -8,8 +8,6 @@ else
C_AGENT="src-agent-c/libdislagent.so" C_AGENT="src-agent-c/libdislagent.so"
fi fi
# ipc.socket is the default communication
# to enable shared memory, remove ",ipc.socket" from the options
java -agentpath:${C_AGENT} \ java -agentpath:${C_AGENT} \
-javaagent:build/dislagent-unspec.jar \ -javaagent:build/dislagent-unspec.jar \
-Xbootclasspath/a:build/dislagent-unspec.jar:build/dislinstr.jar \ -Xbootclasspath/a:build/dislagent-unspec.jar:build/dislinstr.jar \
......
...@@ -143,14 +143,14 @@ static void parse_agent_options(char *options) { ...@@ -143,14 +143,14 @@ static void parse_agent_options(char *options) {
// convert number // convert number
int fitsP = strlen(port_start) < sizeof(port_number); int fitsP = strlen(port_start) < sizeof(port_number);
check_std_error(fitsP, FALSE, "Port number is too long"); check_error(! fitsP, "Port number is too long");
strcpy(port_number, port_start); strcpy(port_number, port_start);
} }
// check if host_name is big enough // check if host_name is big enough
int fitsH = strlen(options) < sizeof(host_name); int fitsH = strlen(options) < sizeof(host_name);
check_std_error(fitsH, FALSE, "Host name is too long"); check_error(! fitsH, "Host name is too long");
strcpy(host_name, options); strcpy(host_name, options);
} }
...@@ -237,7 +237,7 @@ static connection_item * open_connection() { ...@@ -237,7 +237,7 @@ static connection_item * open_connection() {
// get host address // get host address
struct addrinfo * addr; struct addrinfo * addr;
int gai_res = getaddrinfo(host_name, port_number, NULL, &addr); int gai_res = getaddrinfo(host_name, port_number, NULL, &addr);
check_std_error(gai_res == 0, FALSE, gai_strerror(gai_res)); check_error(gai_res != 0, gai_strerror(gai_res));
// create stream socket // create stream socket
int sockfd = socket(addr->ai_family, SOCK_STREAM, 0); int sockfd = socket(addr->ai_family, SOCK_STREAM, 0);
......
...@@ -14,8 +14,22 @@ ...@@ -14,8 +14,22 @@
#define FALSE 0 #define FALSE 0
// error nums // error nums
#define ERR_JVMTI 10001 #define ERR 10000
#define ERR_COMM 10002 #define ERR_STD 10002
#define ERR_JVMTI 10003
/*
* Reports error if condition is true
*/
void check_error(int cond, const char *str) {
if (cond) {
fprintf(stderr, "%s%s\n", ERR_PREFIX, str);
exit(ERR);
}
}
/* /*
* Check error routine - reporting on one place * Check error routine - reporting on one place
...@@ -32,7 +46,7 @@ void check_std_error(int retval, int errorval, const char *str) { ...@@ -32,7 +46,7 @@ void check_std_error(int retval, int errorval, const char *str) {
perror(msgbuf); perror(msgbuf);
exit(ERR_COMM); exit(ERR_STD);
} }
} }
......
...@@ -52,6 +52,10 @@ import ch.usi.dag.disl.utilinstr.tlvinserter.TLVInserter; ...@@ -52,6 +52,10 @@ import ch.usi.dag.disl.utilinstr.tlvinserter.TLVInserter;
import ch.usi.dag.disl.weaver.Weaver; import ch.usi.dag.disl.weaver.Weaver;
// TODO javadoc comment all // TODO javadoc comment all
/**
* Main DiSL class providing interface for an instrumentation framework
* (normally DiSL Server)
*/
public class DiSL { public class DiSL {
public final String PROP_DEBUG = "debug"; public final String PROP_DEBUG = "debug";
...@@ -77,6 +81,10 @@ public class DiSL { ...@@ -77,6 +81,10 @@ public class DiSL {
private final List<Snippet> snippets; private final List<Snippet> snippets;
/**
* DiSL initialization
* @param useDynamicBypass enable or disable dynamic bypass instrumentation
*/
// this method should be called only once // this method should be called only once
public DiSL(boolean useDynamicBypass) throws DiSLException { public DiSL(boolean useDynamicBypass) throws DiSLException {
...@@ -144,6 +152,10 @@ public class DiSL { ...@@ -144,6 +152,10 @@ public class DiSL {
// specify this for InstructionMarker // specify this for InstructionMarker
} }
/**
* Finds transformer class in configuration and allocates it.
* @return newly allocated transformer.
*/
private Transformer resolveTransformer() throws ManifestInfoException, private Transformer resolveTransformer() throws ManifestInfoException,
ReflectionException { ReflectionException {
...@@ -191,8 +203,6 @@ public class DiSL { ...@@ -191,8 +203,6 @@ public class DiSL {
* class that will be instrumented * class that will be instrumented
* @param methodNode * @param methodNode
* method in the classNode argument, that will be instrumented * method in the classNode argument, that will be instrumented
* @param staticContextInstances
*
*/ */
private boolean instrumentMethod(ClassNode classNode, MethodNode methodNode) private boolean instrumentMethod(ClassNode classNode, MethodNode methodNode)
throws ReflectionException, StaticContextGenException, throws ReflectionException, StaticContextGenException,
...@@ -311,6 +321,13 @@ public class DiSL { ...@@ -311,6 +321,13 @@ public class DiSL {
return true; return true;
} }
/**
* Selects only shadows matching the passed guard.
*
* @param guard guard, on witch conditions are the shadows selected
* @param marking the list of shadows from where the gurads selects
* @return selected shadows
*/
private List<Shadow> selectShadowsWithGuard(Method guard, private List<Shadow> selectShadowsWithGuard(Method guard,
List<Shadow> marking) { List<Shadow> marking) {
...@@ -332,6 +349,9 @@ public class DiSL { ...@@ -332,6 +349,9 @@ public class DiSL {
return selectedMarking; return selectedMarking;
} }
/**
* Data holder for an instrumented class
*/
private static class InstrumentedClass { private static class InstrumentedClass {
private ClassNode classNode; private ClassNode classNode;
...@@ -353,7 +373,15 @@ public class DiSL { ...@@ -353,7 +373,15 @@ public class DiSL {
} }
} }
// this method is thread safe after initialization /**
* Instruments class node.
*
* Note: This method is thread safe. Parameter classNode is changed during
* the invocation.
*
* @param classNode class node to instrument
* @return instrumented class
*/
private InstrumentedClass instrumentClass(ClassNode classNode) private InstrumentedClass instrumentClass(ClassNode classNode)
throws DiSLException { throws DiSLException {
...@@ -416,6 +444,12 @@ public class DiSL { ...@@ -416,6 +444,12 @@ public class DiSL {
return null; return null;
} }
/**
* Instruments array of bytes representing a class
*
* @param classAsBytes class as array of bytes
* @return instrumeted class as array of bytes
*/
public byte[] instrument(byte[] classAsBytes) throws DiSLException { public byte[] instrument(byte[] classAsBytes) throws DiSLException {
// output bytes into the file // output bytes into the file
...@@ -511,6 +545,9 @@ public class DiSL { ...@@ -511,6 +545,9 @@ public class DiSL {
return cw.toByteArray(); return cw.toByteArray();
} }
/**
* Termination handler - should be invoked by the instrumentation framework
*/
public void terminate() { public void terminate() {
} }
......
...@@ -2,6 +2,22 @@ package ch.usi.dag.disl.annotation; ...@@ -2,6 +2,22 @@ package ch.usi.dag.disl.annotation;
import ch.usi.dag.disl.marker.Marker; import ch.usi.dag.disl.marker.Marker;
/**
* The After annotation instructs DiSL to insert the snippet body after the
* marked region. The snippet will be invoked after a normal exit of the region
* or after an exit caused by an exception.
*
* NOTE: This is only general contract. It depends on particular marker how the
* contract will be implemented.
*
* This annotation should be used with methods.
*
* The method should be static, not return any values and not throw any
* exceptions.
*
* Method argument can be StaticContext, DynamicContext, ClassContext and
* ArgumentProcessorContext.
*/
public @interface After { public @interface After {
// NOTE if you want to change names, you need to change // NOTE if you want to change names, you need to change
...@@ -9,13 +25,52 @@ public @interface After { ...@@ -9,13 +25,52 @@ public @interface After {
// NOTE because of implementation of annotations in java the defaults // NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above // are not retrieved from here but from class mentioned above
/**
* Marker class defines a region where the snippet is applied.
*/
Class<? extends Marker> marker(); Class<? extends Marker> marker();
/**
* Argument for the marker (as string).
*
* Default value: ""
*/
String args() default ""; // cannot be null :( String args() default ""; // cannot be null :(
/**
* Scope of the methods, where the snippet is applied.
*
* @see ch.usi.dag.disl.scope package for more info about scoping language.
*
* Default value: "*"
*/
String scope() default "*"; String scope() default "*";
/**
* The guard class defining if the snippet will be inlined in particular
* region or not.
*
* Default value: Object.class - means none
*/
Class<? extends Object> guard() default Object.class; // cannot be null :( Class<? extends Object> guard() default Object.class; // cannot be null :(
/**
* Defines ordering of the snippets. Smaller number indicates that snippet
* will be inlined closer to the instrumented code.
*
* Default value: 100
*/
int order() default 100; int order() default 100;
// NOTE that activation of dynamic bypass is decided by the instrumentation
// framework in first place /**
* Advanced option. You can in general disable dynamic bypass on snippets,
* that are not using any other class.
*
* NOTE Usage of dynamic bypass is determined by the underlying
* instrumentation framework.
*
* Default value: true
*/
boolean dynamicBypass() default true; boolean dynamicBypass() default true;
} }
...@@ -2,6 +2,22 @@ package ch.usi.dag.disl.annotation; ...@@ -2,6 +2,22 @@ package ch.usi.dag.disl.annotation;
import ch.usi.dag.disl.marker.Marker; import ch.usi.dag.disl.marker.Marker;
/**
* The AfterReturning annotation instructs DiSL to insert the snippet body after
* the marked region. The snippet will be invoked after a normal exit of the
* region.
*
* NOTE: This is only general contract. It depends on particular marker how the
* contract will be implemented.
*
* This annotation should be used with methods.
*
* The method should be static, not return any values and not throw any
* exceptions.
*
* Method argument can be StaticContext, DynamicContext, ClassContext and
* ArgumentProcessorContext.
*/
public @interface AfterReturning { public @interface AfterReturning {
// NOTE if you want to change names, you need to change // NOTE if you want to change names, you need to change
...@@ -10,12 +26,51 @@ public @interface AfterReturning { ...@@ -10,12 +26,51 @@ public @interface AfterReturning {
// NOTE because of implementation of annotations in java the defaults // NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above // are not retrieved from here but from class mentioned above
/**
* Marker class defines a region where the snippet is applied.
*/
Class<? extends Marker> marker(); Class<? extends Marker> marker();
/**
* Argument for the marker (as string).
*
* Default value: ""
*/
String args() default ""; // cannot be null :( String args() default ""; // cannot be null :(
/**
* Scope of the methods, where the snippet is applied.
*
* @see ch.usi.dag.disl.scope package for more info about scoping language.
*
* Default value: "*"
*/
String scope() default "*"; String scope() default "*";
/**
* The guard class defining if the snippet will be inlined in particular
* region or not.
*
* Default value: Object.class - means none
*/
Class<? extends Object> guard() default Object.class; // cannot be null :( Class<? extends Object> guard() default Object.class; // cannot be null :(
/**
* Defines ordering of the snippets. Smaller number indicates that snippet
* will be inlined closer to the instrumented code.
*
* Default value: 100
*/
int order() default 100; int order() default 100;
// NOTE that activation of dynamic bypass is decided by the instrumentation
// framework in first place /**
* Advanced option. You can in general disable dynamic bypass on snippets,
* that are not using any other class.
*
* NOTE Usage of dynamic bypass is determined by the underlying
* instrumentation framework.
*
* Default value: true
*/
boolean dynamicBypass() default true; boolean dynamicBypass() default true;
} }
...@@ -2,6 +2,22 @@ package ch.usi.dag.disl.annotation; ...@@ -2,6 +2,22 @@ package ch.usi.dag.disl.annotation;
import ch.usi.dag.disl.marker.Marker; import ch.usi.dag.disl.marker.Marker;
/**
* The AfterThrowing annotation instructs DiSL to insert the snippet body after
* the marked region. The snippet will be invoked after an exit caused by an
* exception.
*
* NOTE: This is only general contract. It depends on particular marker how the
* contract will be implemented.
*
* This annotation should be used with methods.
*
* The method should be static, not return any values and not throw any
* exceptions.
*
* Method argument can be StaticContext, DynamicContext, ClassContext and
* ArgumentProcessorContext.
*/
public @interface AfterThrowing { public @interface AfterThrowing {
// NOTE if you want to change names, you need to change // NOTE if you want to change names, you need to change
...@@ -10,12 +26,51 @@ public @interface AfterThrowing { ...@@ -10,12 +26,51 @@ public @interface AfterThrowing {
// NOTE because of implementation of annotations in java the defaults // NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above // are not retrieved from here but from class mentioned above
/**
* Marker class defines a region where the snippet is applied.
*/
Class<? extends Marker> marker(); Class<? extends Marker> marker();
/**
* Argument for the marker (as string).
*
* Default value: ""
*/
String args() default ""; // cannot be null :( String args() default ""; // cannot be null :(
/**
* Scope of the methods, where the snippet is applied.
*
* @see ch.usi.dag.disl.scope package for more info about scoping language.
*
* Default value: "*"
*/
String scope() default "*"; String scope() default "*";
/**
* The guard class defining if the snippet will be inlined in particular
* region or not.
*
* Default value: Object.class - means none
*/
Class<? extends Object> guard() default Object.class; // cannot be null :( Class<? extends Object> guard() default Object.class; // cannot be null :(
/**
* Defines ordering of the snippets. Smaller number indicates that snippet
* will be inlined closer to the instrumented code.
*
* Default value: 100
*/
int order() default 100; int order() default 100;
// NOTE that activation of dynamic bypass is decided by the instrumentation
// framework in first place /**
* Advanced option. You can in general disable dynamic bypass on snippets,
* that are not using any other class.
*
* NOTE Usage of dynamic bypass is determined by the underlying
* instrumentation framework.
*
* Default value: true
*/
boolean dynamicBypass() default true; boolean dynamicBypass() default true;
} }
package ch.usi.dag.disl.annotation; package ch.usi.dag.disl.annotation;
/**
* Annotated class defines method for processing method arguments. The specified
* methods will be inlined into snippets to process one method argument value.
*
* First argument of the method is a type, that will be processed by the method.
* The allowed types are all basic types, String and Object class. The processed
* type can be extend in some special cases by ProcessAlso annotation.
* During run-time, the argument will contain a processed method argument value.
*
* ArgumentContext can be used to fetch additional data about the argument.
*
* This annotation should be used with classes.
*
* The method should be static, not return any values and not throw any
* exceptions.
*
* Method argument can be StaticContext, DynamicContext, ClassContext and
* ArgumentContext.
*/
public @interface ArgumentProcessor { public @interface ArgumentProcessor {
} }
...@@ -2,6 +2,21 @@ package ch.usi.dag.disl.annotation; ...@@ -2,6 +2,21 @@ package ch.usi.dag.disl.annotation;
import ch.usi.dag.disl.marker.Marker; import ch.usi.dag.disl.marker.Marker;
/**
* The Before annotation instructs DiSL to insert the snippet body before the
* marked region. The snippet will be invoked before the entry of the region.
*
* NOTE: This is only general contract. It depends on particular marker how the
* contract will be implemented.
*
* This annotation should be used with methods.
*
* The method should be static, not return any values and not throw any
* exceptions.
*
* Method argument can be StaticContext, DynamicContext, ClassContext and
* ArgumentProcessorContext.
*/
public @interface Before { public @interface Before {
// NOTE if you want to change names, you need to change // NOTE if you want to change names, you need to change
...@@ -10,12 +25,51 @@ public @interface Before { ...@@ -10,12 +25,51 @@ public @interface Before {
// NOTE because of implementation of annotations in java the defaults // NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above // are not retrieved from here but from class mentioned above
/**
* Marker class defines a region where the snippet is applied.
*/
Class<? extends Marker> marker(); Class<? extends Marker> marker();
/**
* Argument for the marker (as string).
*
* Default value: ""
*/
String args() default ""; // cannot be null :( String args() default ""; // cannot be null :(
/**
* Scope of the methods, where the snippet is applied.
*
* @see ch.usi.dag.disl.scope package for more info about scoping language.
*
* Default value: "*"
*/
String scope() default "*"; String scope() default "*";
/**
* The guard class defining if the snippet will be inlined in particular
* region or not.
*
* Default value: Object.class - means none
*/
Class<? extends Object> guard() default Object.class; // cannot be null :( Class<? extends Object> guard() default Object.class; // cannot be null :(
/**
* Defines ordering of the snippets. Smaller number indicates that snippet
* will be inlined closer to the instrumented code.
*
* Default value: 100
*/
int order() default 100; int order() default 100;
// NOTE that activation of dynamic bypass is decided by the instrumentation
// framework in first place /**
* Advanced option. You can in general disable dynamic bypass on snippets,
* that are not using any other class.
*
* NOTE Usage of dynamic bypass is determined by the underlying
* instrumentation framework.
*
* Default value: true
*/
boolean dynamicBypass() default true; boolean dynamicBypass() default true;
} }
...@@ -6,10 +6,12 @@ import java.lang.annotation.RetentionPolicy; ...@@ -6,10 +6,12 @@ import java.lang.annotation.RetentionPolicy;
/** /**
* Marks guard validation method. * Marks guard validation method.
* *
* This annotation should be used with methods.
*
* Guard method should be static and state-less. * Guard method should be static and state-less.
* *
* Method argument can be Shadow, StaticContext and for ArgumentProcessor guard * Method argument can be Shadow, StaticContext, GuardContext and for
* also ArgumentContext. * ArgumentProcessor guard also ArgumentContext.
*/ */
@Retention(RetentionPolicy.RUNTIME) // to resolve annotation using reflection @Retention(RetentionPolicy.RUNTIME) // to resolve annotation using reflection
public @interface GuardMethod { public @interface GuardMethod {
......
package ch.usi.dag.disl.annotation; package ch.usi.dag.disl.annotation;
/**
* Annotation used in ArgumentProcessor to guard specific methods.
*
* This annotation should be used with methods.
*/
public @interface Guarded { public @interface Guarded {
// NOTE if you want to change names, you need to change // NOTE if you want to change names, you need to change
...@@ -7,6 +12,8 @@ public @interface Guarded { ...@@ -7,6 +12,8 @@ public @interface Guarded {
// NOTE because of implementation of annotations in java the defaults // NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above // are not retrieved from here but from class mentioned above
/**
* The guard class defining if the processor method will be inlined or not.
*/
Class<? extends Object> guard(); Class<? extends Object> guard();
} }
...@@ -2,6 +2,11 @@ package ch.usi.dag.disl.annotation; ...@@ -2,6 +2,11 @@ package ch.usi.dag.disl.annotation;
// TODO add tool that will look for Instrumentation annotation and create meta-data for jar // TODO add tool that will look for Instrumentation annotation and create meta-data for jar
// http://stackoverflow.com/questions/3644069/java-6-annotation-processing-configuration-with-ant // http://stackoverflow.com/questions/3644069/java-6-annotation-processing-configuration-with-ant
/**
* This method denotes DiSL instrumentation class.
*
* This annotation should be used with classes.
*/
public @interface Instrumentation { public @interface Instrumentation {
} }
package ch.usi.dag.disl.annotation; package ch.usi.dag.disl.annotation;
/**
* If attached to the processor method, it allows to process:
* short, byte and boolean in int processor,
* byte and boolean in short processor,
* boolean in byte processor.
*/
public @interface ProcessAlso { public @interface ProcessAlso {
// NOTE if you want to change names, you need to change // NOTE if you want to change names, you need to change
......
package ch.usi.dag.disl.annotation; package ch.usi.dag.disl.annotation;
// NOTE: Initialization can be done only within field definition /**
// - java static { } construct for initialization is not supported and * Indicates, that field is used for data passing between several snippets