Document directory
- Attach to JVM, load agent
- Instrumentation
- Attach and instument
- Btrace content
Procedure:
1. btrace parses the script and generates the corresponding agent package
2. Attach to JVM, load the agent package, and execute the premain or agentmain method. The input parameters include
3. ASM enhanced code
4. Replace Instrument
Attach to JVM, load agent
Obtain JVM through JVM Ti API
JVM Ti startup method:
A. Load the shared library directly through parameters at startup
B. Use Java attach to trigger the JVM source thread attach listener to execute the callback function of the dynamic module.
Method A introduces the following callback functions: jniexport jint jnicallagent_onload (JavaVM * Vm, char * options, void * Reserved) Method B introduces the following callback functions: jniexport jint jnicallagent_onattach (JavaVM * JVM, char * options, void * Reserved) {callback function when the shared library is detached (common): jniexport void jnicall agent_onunload (JavaVM * VM, the callback functions provided by method A and method B have the same parameters.
Instrumentation
The specific implementation of the "Java. Lang. Instrument" package depends on jvmti.
** There are two ways to obtain an instance of the * instrumentation interface: *** when a JVM is launched in a way that indicates an agent * class. in that case an instrumentation instance * is passed to the premain method of the agent class. ** when a JVM provides a mechanic to start agents sometime * after the JVM is launched. in that case an instrumentation * instance is passed to the agentmain method of the * agent code. * *** this method operates on * a set in order to allow interdependent changes to more than one class at the same time * (a retransformation of Class A can require a retransformation of Class B ). * Note: cascade modifications may exist. ** if a retransformed method has active stack frames, those active frames continue to * run the bytecodes of the original method. * The retransformed method will be used on new invokes. * Note: For self-execution methods, the previous method is used for the next execution, the next time you start to apply the new ** this method does not cause any initialization before t that which wowould occur * under the customary JVM semantics. in other words, redefining a class * does not cause its initializers to be run. the values of static variables * will remain as they were prior to the call. * Note: initialization will not occur. ** instances of the retransformed class are not affected. * ** the retransformation may change method bodies, the constant pool and attributes. * The retransformation must not add, remove or rename fields or methods, change the * Signatures of methods, or change inheritance. these restrictions maybe * lifted in future versions. the class file bytes are not checked, verified and installed * until after the transformations have been applied, if the resultant bytes are in * error this method will throw an exception. * Note: there are some restrictions. * void retransformclasses (class... classes) throws unmodifiableclassexception;
In Java SE 5, through the premain method, you can only do something before executing main. Then, use the tranceform method of classfiletransformer to replace and convert the class definition.
Among the instrumentation of Java SE 6, there is a "agentmain" method that is "in parallel" with premain ", which can be run after the main function starts to run. It can be very happy to work with attach!
Attach and instument
- First, define the relevant transformer to replace the bytecode. You can use classname to determine which classes and other functions to replace.
class Transformer implements ClassFileTransformer
- Then define the agent package. After the jar package is generated, specify the agent-class: agentmain in the manifest file.
public class AgentMain { public static void agentmain(String agentArgs, Instrumentation inst) throws ClassNotFoundException, UnmodifiableClassException, InterruptedException { inst.addTransformer(new Transformer (), true); inst.retransformClasses(TransClass.class); System.out.println("Agent Main Done"); }}
- Then load the generated agent package through attach
vm = VirtualMachine.attach(vmd); vm.loadAgent(jar); vm.detach();
- After the agent package is loaded, the agentmain function and end function are executed through the callback function.
Btrace content
In the main class, both premain and agentmain call the main method.
Public static void premain (string ARGs, instrumentation insT) {main (ARGs, insT);} public static void agentmain (string ARGs, instrumentation insT) {main (ARGs, insT );} private Static synchronized void main (final string ARGs, final instrumentation insT) content in main: Private Static synchronized void main (final string ARGs, final instrumentation insT ){... parseargs (ARGs); Note: parse the input parameter string bootclasspath = argmap. get ("bootclasspath ");... inst. appendtobootstrapclassloadersearch (New jarfile (new file (PATH); string systemclasspath = argmap. get ("systemclasspath ");... inst. appendtosystemclassloadersearch (New jarfile (new file (PATH); Note: add the search path of bootstrapclassloader/systemclassloader... thread agentthread = new thread (New runnable () {public void run () {btraceruntime. enter (); try {startserver () ;}finally {btraceruntime. leave () ;}}); btraceruntime. enter ();... agentthread. start (); ========================================================== =========== Private Static void startserver () {int Port = btrace_default_port ;... serversocket SS; try {system. setproperty ("btrace. port ", String. valueof (port ));... ss = new serversocket (port); Note: Create link} catch (ioexception ioexp ){...} socket sock = ss. accept (); Client client = new remoteclient (Inst, sock); registerexithook (client); Note: at runtime. add the shutdown hook handlenewclient (client) to getruntime (); Note :} ========================================================== ===================== Private Static void handlenewclient (final Client client) {serializedexecutor. submit (New runnable () {public void run () {try {If (client. shouldaddtransformer () {Inst. addtransformer (client, true); Class [] classes = Inst. getallloadedclasses (); Note: Get the loaded class arraylist list = new arraylist (); For (Class C: classes) {If (Inst. ismodifiableclass (c) & client. iscandidate (c) {list. add (c) ;}} Note: Get the class int size to be modified = List. size (); If (size> 0) {classes = new class [size]; List. toarray (classes); client. startretransformclasses (size); Note: replace class with Inst. retransformclasses (classes); client. skipretransforms () ;}} client. getruntime (). send (New okaycommand ();} catch (unmodifiableclassexception UCE ){...}}});