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"?>
<projectDescription>
<name>disl</name>
<name>DiSL</name>
<comment></comment>
<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
C_AGENT="src-agent-c/libdislagent.so"
fi
# ipc.socket is the default communication
# to enable shared memory, remove ",ipc.socket" from the options
java -agentpath:${C_AGENT} \
-javaagent:build/dislagent-unspec.jar \
-Xbootclasspath/a:build/dislagent-unspec.jar:build/dislinstr.jar \
......
......@@ -143,14 +143,14 @@ static void parse_agent_options(char *options) {
// convert 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);
}
// check if host_name is big enough
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);
}
......@@ -237,7 +237,7 @@ static connection_item * open_connection() {
// get host address
struct addrinfo * 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
int sockfd = socket(addr->ai_family, SOCK_STREAM, 0);
......
......@@ -14,8 +14,22 @@
#define FALSE 0
// error nums
#define ERR_JVMTI 10001
#define ERR_COMM 10002
#define ERR 10000
#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
......@@ -32,7 +46,7 @@ void check_std_error(int retval, int errorval, const char *str) {
perror(msgbuf);
exit(ERR_COMM);
exit(ERR_STD);
}
}
......
......@@ -52,6 +52,10 @@ import ch.usi.dag.disl.utilinstr.tlvinserter.TLVInserter;
import ch.usi.dag.disl.weaver.Weaver;
// TODO javadoc comment all
/**
* Main DiSL class providing interface for an instrumentation framework
* (normally DiSL Server)
*/
public class DiSL {
public final String PROP_DEBUG = "debug";
......@@ -77,6 +81,10 @@ public class DiSL {
private final List<Snippet> snippets;
/**
* DiSL initialization
* @param useDynamicBypass enable or disable dynamic bypass instrumentation
*/
// this method should be called only once
public DiSL(boolean useDynamicBypass) throws DiSLException {
......@@ -144,6 +152,10 @@ public class DiSL {
// specify this for InstructionMarker
}
/**
* Finds transformer class in configuration and allocates it.
* @return newly allocated transformer.
*/
private Transformer resolveTransformer() throws ManifestInfoException,
ReflectionException {
......@@ -191,8 +203,6 @@ public class DiSL {
* class that will be instrumented
* @param methodNode
* method in the classNode argument, that will be instrumented
* @param staticContextInstances
*
*/
private boolean instrumentMethod(ClassNode classNode, MethodNode methodNode)
throws ReflectionException, StaticContextGenException,
......@@ -311,6 +321,13 @@ public class DiSL {
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,
List<Shadow> marking) {
......@@ -332,6 +349,9 @@ public class DiSL {
return selectedMarking;
}
/**
* Data holder for an instrumented class
*/
private static class InstrumentedClass {
private ClassNode classNode;
......@@ -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)
throws DiSLException {
......@@ -416,6 +444,12 @@ public class DiSL {
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 {
// output bytes into the file
......@@ -511,6 +545,9 @@ public class DiSL {
return cw.toByteArray();
}
/**
* Termination handler - should be invoked by the instrumentation framework
*/
public void terminate() {
}
......
......@@ -2,6 +2,22 @@ package ch.usi.dag.disl.annotation;
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 {
// NOTE if you want to change names, you need to change
......@@ -9,13 +25,52 @@ public @interface After {
// NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above
/**
* Marker class defines a region where the snippet is applied.
*/
Class<? extends Marker> marker();
/**
* Argument for the marker (as string).
*
* Default value: ""
*/
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 "*";
/**
* 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 :(
/**
* 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;
// 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;
}
......@@ -2,6 +2,22 @@ package ch.usi.dag.disl.annotation;
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 {
// NOTE if you want to change names, you need to change
......@@ -10,12 +26,51 @@ public @interface AfterReturning {
// NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above
/**
* Marker class defines a region where the snippet is applied.
*/
Class<? extends Marker> marker();
/**
* Argument for the marker (as string).
*
* Default value: ""
*/
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 "*";
/**
* 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 :(
/**
* 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;
// 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;
}
......@@ -2,6 +2,22 @@ package ch.usi.dag.disl.annotation;
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 {
// NOTE if you want to change names, you need to change
......@@ -10,12 +26,51 @@ public @interface AfterThrowing {
// NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above
/**
* Marker class defines a region where the snippet is applied.
*/
Class<? extends Marker> marker();
/**
* Argument for the marker (as string).
*
* Default value: ""
*/
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 "*";
/**
* 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 :(
/**
* 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;
// 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;
}
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 {
}
......@@ -2,6 +2,21 @@ package ch.usi.dag.disl.annotation;
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 {
// NOTE if you want to change names, you need to change
......@@ -10,12 +25,51 @@ public @interface Before {
// NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above
/**
* Marker class defines a region where the snippet is applied.
*/
Class<? extends Marker> marker();
/**
* Argument for the marker (as string).
*
* Default value: ""
*/
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 "*";
/**
* 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 :(
/**
* 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;
// 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;
}
......@@ -6,10 +6,12 @@ import java.lang.annotation.RetentionPolicy;
/**
* Marks guard validation method.
*
* This annotation should be used with methods.
*
* Guard method should be static and state-less.
*
* Method argument can be Shadow, StaticContext and for ArgumentProcessor guard
* also ArgumentContext.
* Method argument can be Shadow, StaticContext, GuardContext and for
* ArgumentProcessor guard also ArgumentContext.
*/
@Retention(RetentionPolicy.RUNTIME) // to resolve annotation using reflection
public @interface GuardMethod {
......
package ch.usi.dag.disl.annotation;
/**
* Annotation used in ArgumentProcessor to guard specific methods.
*
* This annotation should be used with methods.
*/
public @interface Guarded {
// NOTE if you want to change names, you need to change
......@@ -7,6 +12,8 @@ public @interface Guarded {
// NOTE because of implementation of annotations in java the defaults
// 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();
}
......@@ -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
// 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 {
}
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 {
// NOTE if you want to change names, you need to change
......
package ch.usi.dag.disl.annotation;
// NOTE: Initialization can be done only within field definition
// - java static { } construct for initialization is not supported and
// will cause invalid instrumentation
/**
* Indicates, that field is used for data passing between several snippets
* inlined into one method. The field is translated into local variable within
* a method. The local variable is by default always initialized to the assigned
* value or the default value of a corresponding type. It is possible to disable
* the initialization using optional "initialize" annotation parameter.
*
* NOTE: Initialization can be done only within field definition.
* Java static { } construct for initialization is not supported and
* could cause invalid instrumentation.
*
* This annotation should be used with fields.
*
* Field should be declared as static, and if not shared between multiple DiSL
* classes, also private.
*/
public @interface SyntheticLocal {
public enum Initialize {
......@@ -15,5 +28,10 @@ public @interface SyntheticLocal {
// NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above
/**
* Initialization mode of the SyntheticLocal variable.
*
* Default value: Initialize.ALWAYS
*/
Initialize initialize() default(Initialize.ALWAYS);
}
package ch.usi.dag.disl.annotation;
/**
* Indicates, that field is used for data passing between several snippets
* inlined. The field is translated into thread local variable. The thread local
* variable is by default always initialized the default value of a
* corresponding type. The default value can be inherited from a parent thread
* using optional inheritable annotation parameter.
*
* This annotation should be used with fields.
*
* Field should be declared as static, and if not shared between multiple DiSL
* classes, also private.
*/
public @interface ThreadLocal {
// NOTE if you want to change names, you need to change
......@@ -8,5 +20,10 @@ public @interface ThreadLocal {
// NOTE because of implementation of annotations in java the defaults
// are not retrieved from here but from class mentioned above
/**
* Indicates, weather is the default value inherited from a parent thread.
*
* Default value: false
*/
boolean inheritable() default(false);
}
package ch.usi.dag.disl.classcontext;
/**
* Allows convert Strings to Class objects. The context is allowed in
* snippets and argument processors
* Allows converting Strings to Class objects.
*/
public interface ClassContext {
/**
* Converts string name to the class object.
*
* @param name string containing name of the class
* @return class object
*/
Class<?> asClass(String name);
}
package ch.usi.dag.disl.dynamiccontext;
/**
* Dynamic context provides access to dynamic information of the snippet.
*/
public interface DynamicContext {
/**
......
......@@ -129,6 +129,8 @@ public abstract class ExclusionSet {
}
}
jarFile.close();
return exclSet;
} catch(IOException e) {
......
package ch.usi.dag.disl.guardcontext;
/**
* Guard context is used to invoke guard inside of other guard.
*/
public interface GuardContext {
/**
* Invokes guard passed as argument
*
* @param guardClass guard to invoke
* @return result of the invoked guard
*/
boolean invoke(Class<?> guardClass);
}
......@@ -4,6 +4,13 @@ import java.util.List;
import org.objectweb.asm.tree.MethodNode;
/**
* AbstractDWRMarker is an enhancement of AbstractMarker automatically computing
* weaving region. This includes correct position of end region (not after jump)
* and meaningful try block.
*
* User has to implement markWithDefaultWeavingReg method.
*/
public abstract class AbstractDWRMarker extends AbstractMarker{
public final List<MarkedRegion> mark(MethodNode methodNode) {
......@@ -19,10 +26,11 @@ public abstract class AbstractDWRMarker extends AbstractMarker{
}
/**
* Implementing this method will affect all marked regions.
* Implementation of this method should return list of marked regions
* with filled start and end of the region.
*
* The regions will get automatic after throw computation
* The regions will get automatic branch skipping at the end
* The regions will get automatic after throw computation.
* The regions will get automatic branch skipping at the end.
*/
public abstract List<MarkedRegion> markWithDefaultWeavingReg(
MethodNode methodNode);
......
......@@ -17,9 +17,19 @@ import ch.usi.dag.disl.snippet.Shadow.WeavingRegion;
import ch.usi.dag.disl.snippet.Snippet;
import ch.usi.dag.disl.util.AsmHelper;
/**
* AbstractMarker eases the effort to implement new marker by providing mark
* method returning MarkedRegion class instead of Shadow. The MarkedRegion
* class itself supports automatic computation of weaving region based
* simplified region specification.