![]() | ![]() | ![]() | Dynamic Analysis |
This chapter describes all aspect of dynamic analysis in Chord. Section * describes how to write a dynamic analysis, Section * describes how to compile and run it, and Section * describes common dynamic analysis events supported in Chord.
Follow the following steps to write your own dynamic analysis.
Create a class extending chord.project.analyses.DynamicAnalysis and override the appropriate methods in it. The only methods that must be compulsorily overridden are method getInstrScheme(), which must return an instance of the "instrumentation scheme" required by your dynamic analysis (i.e., the kind and format of events to be generated during an instrumented program's execution) plus each process<event>(<args>) method that corresponds to event <event> with format <args> enabled by the chosen instrumentation scheme. See Section * for the kinds of supported events and their formats.
A sample such class MyDynamicAnalysis is shown below:
import chord.project.Chord; import chord.project.analyses.DynamicAnalysis; import chord.instr.InstrScheme; // ***TODO***: analysis won't be recognized by Chord without this annotation @Chord(name = "<ANALYSIS_NAME>") public class MyDynamicAnalysis extends DynamicAnalysis { InstrScheme scheme; @Override public InstrScheme getInstrScheme() { if (scheme != null) return scheme; scheme = new InstrScheme(); // ***TODO***: Choose (<event1>, <args1>), ... (<eventN>, <argsN>) // depending upon the kind and format of events required by this // dynamic analysis to be generated for this during an instrumented // program's execution. scheme.set<event1>(<args1>); ... scheme.set<eventN>(<argsN>); return scheme; } @Override public void initAllPasses() { // ***TODO***: User code to be executed once and for all // before all instrumented program runs start. } @Override public void doneAllPasses() { // ***TODO***: User code to be executed once and for all // after all instrumented program runs finish. } @Override public void initPass() { // ***TODO***: User code to be executed once before each instrumented program run starts. } @Override public void donePass() { // ***TODO***: User code to be executed once after each instrumented program run finishes. } @Override public void process<event1>(<args1>) { // ***TODO***: User code for handling events of kind <event1> with format <args1>. } ... @Override public void process<eventN>(<argsN>) { // ***TODO***: User code for handling events of kind <eventN> with format <argsN>. } } |
Compile the analysis by placing the directory containing class MyDynamicAnalysis created above in the path defined by property chord.ext.java.analysis.path.
Provide the IDs of program runs to be generated (say 1, 2, ..., M) and the command-line arguments to be used for the program in each of those runs (say <args1>, ..., <argsM>) via properties chord.run.ids=1,2,...,N and chord.args.1=<args1>, ..., chord.args.M=<argsM>. By default, chord.run.ids=0 and chord.args.0="", that is, the program will be run only once (using run ID 0) with no command-line arguments.
To run the analysis, set property chord.run.analyses to <ANALYSIS_NAME> (recall that <ANALYSIS_NAME> is the name provided in the @Chord annotation for class MyDynamicAnalysis created above).
Note: The IBM J9 JVM on Linux is highly recommended if you intend to use Chord for dynamic program analysis, as it allows you to instrument the entire JDK; using any other platform will likely require excluding large parts of the JDK from being instrumented. Additionally, if you intend to use online (load-time) bytecode instrumentation in your dynamic program analysis, then you will need JDK 6 or higher, since this functionality requires the java.lang.instrument API with class retransformation support (the latter support is available only in JDK 6 and higher).
You can change the default values of various properties for configuring your dynamic analysis; see Section * and Section * in Chapter *. For instance:
Chord offers much more flexibility in crafting dynamic analyses. You can define your own instrumentor (by subclassing chord.instr.CoreInstrumentor instead of using the default chord.instr.Instrumentor) and your own event handler (by subclassing chord.runtime.CoreEventHandler instead of using the default chord.runtime.EventHandler). You can ask the dynamic analysis to use your custom instrumentor and/or your custom event handler by overriding methods getInstrumentor() and getEventHandler(), respectively, defined in chord.project.analyses.CoreDynamicAnalysis. Finally, you can define your own dynamic analysis template by subclassing chord.project.analyses.CoreDynamicAnalysis instead of subclassing the default chord.project.analyses.DynamicAnalysis.
Chord provides support for instrumenting common dynamic analysis events. The below table describes these events.
Event Kind | Description | ||
EnterMainMethod(t) | After thread t enters method m (in domain M). | ||
EnterMethod(m, t) | After thread t enters method m (in domain M). | ||
LeaveMethod(m, t) | Before thread t leaves method m (in domain M). | ||
EnterLoop(w, t) | Before thread t begins loop w (in domain W). | ||
LoopIteration(w, t) | Before thread t starts a new iteration of loop w (in domain W). | ||
LeaveLoop(w, t) | After thread t finishes loop w (in domain W). | ||
BasicBlock(b, t) | Before thread t enters basic block b (in domain B). | ||
Quad(p, t) | Before thread t executes quad at program point p (in domain P). | ||
BefMethodCall(i, t, o) |
| ||
AftMethodCall(i, t, o) |
| ||
BefNew(h, t, o) | Before thread t executes a new bytecode instruction and allocates fresh object o at program point h (in domain H). | ||
AftNew(h, t, o) | After thread t executes a new bytecode instruction and allocates fresh object o at program point h (in domain H). | ||
NewArray(h, t, o) | After thread t executes a newarray bytecode instruction and allocates fresh object o at program point h (in domain H). | ||
GetstaticPrimitive(e, t, f) | After thread t reads primitive-typed static field f (in domain F) at program point e (in domain E). | ||
GetstaticReference(e, t, f, o) | After thread t reads object o from reference-typed static field f (in domain F) at program point e (in domain E). | ||
PutstaticPrimitive(e, t, f) | After thread t writes primitive-typed static field f (in domain F) at program point e (in domain E). | ||
PutstaticReference(e, t, f, o) | After thread t writes object o to reference-typed static field f (in domain F) at program point e (in domain E). | ||
GetfieldPrimitive(e, t, b, f) | After thread t reads primitive-typed instance field f (in domain F) of object b at program point e (in domain E). | ||
GetfieldReference(e, t, b, f, o) | After thread t reads object o from reference-typed instance field f (in domain F) of object b at program point e (in domain E). | ||
PutfieldPrimitive(e, t, b, f) | After thread t writes primitive-typed instance field f (in domain F) of object b at program point e (in domain E). | ||
PutfieldReference(e, t, b, f, o) | After thread t writes object o to reference-typed instance field f (in domain F) of object b at program point e (in domain E). | ||
AloadPrimitive(e, t, b, i) | After thread t reads the primitive-typed element at index i of array object b at program point e (in domain E). | ||
AloadReference(e, t, b, i, o) | After thread t reads object o from the reference-typed element at index i of array object b at program point e (in domain E). | ||
AstorePrimitive(e, t, b, i) | After thread t writes the primitive-typed element at index i of array object b at program point e (in domain E). | ||
AstoreReference(e, t, b, i, o) | After thread t writes object o to the reference-typed element at index i of array object b at program point e (in domain E). | ||
ThreadStart(i, t, o) | Before thread t calls the start() method of java.lang.Thread at program point i (in domain I) and spawns a thread o. | ||
ThreadJoin(i, t, o) | Before thread t calls the join() method of java.lang.Thread at program point i (in domain I) to join with thread o. | ||
AcquireLock(l, t, o) | After thread t executes a statement of the form "monitorenter o" or enters a method synchronized on o at program point l (in domain L). | ||
ReleaseLock(r, t, o) | Before thread t executes a statement of the form "monitorexit o" or leaves a method synchronized on o at program point r (in domain R). | ||
Wait(i, t, o) | Before thread t calls the wait() method of java.lang.Object on object o at program point i (in domain I). | ||
Notify(i, t, o) | Before thread t calls the notify() or notifyAll() method of java.lang.Object on object o at program point i (in domain I). |
![]() | ![]() | ![]() | Dynamic Analysis |