btrace,看一看btrace

执行步骤:
1. btrace解析script,并生成相应的agent包
2. attach到jvm,并将相关agent包load进行,执行preMain或者agentMain方法,传入参数包括instrument
3. asm强化代码
4. instrument替换

attach到jvm,load agent

通过jvm TI api来获取jvm
jvm TI启动方式:
A. 启动时通过参数直接载入共享库
B. 通过java attach实现,触发JVM源生线程Attach Listener来执行这个dynamic module的回调函数
方式A引入的回调函数如下: JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) 方式B引入的回调函数如下: JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 卸载共享库时的回调函数(通用): JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) 我们可以看到,方式A和方式B提供的回调函数,参数是一样的。

instrumentation

"java.lang.instrument"包的具体实现,依赖于 JVMTI
* * There are two ways to obtain an instance of the * Instrumentation interface: * *
    *
  1. 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. *
  2. *
  3. When a JVM provides a mechanism 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.
  4. *
*
* * This method operates _disibledevent=>
  • load到agent包之后通过回调函数执行agentMain函数,end

btrace中内容

在Main类中的入口方法:premain或者agentmain都会调用main方法
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)
main中的内容:
private static synchronized void main(final String args, final Instrumentation inst) { ... parseArgs(args); 注:解析传入的参数 String bootClassPath = argMap.get("bootClassPath"); ... inst.appendToBootstrapClassLoaderSearch(new JarFile(new File(path))); String systemClassPath = argMap.get("systemClassPath"); ... inst.appendToSystemClassLoaderSearch(new JarFile(new File(path))); 注:增加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); 注:创建链接 } catch (IOException ioexp) { ... } Socket sock = ss.accept(); Client client = new RemoteClient(inst, sock); registerExitHook(client); 注:在Runtime.getRuntime()中添加shutdown的hook handleNewClient(client); 注: } ======================================================== 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(); 注:获取已加载的class ArrayList list = new ArrayList(); for (Class c : classes) { if (inst.isModifiableClass(c) && client.isCandidate(c)) { list.add(c); } } 注:获取要修改的class int size = list.size(); if (size > 0) { classes = new Class[size]; list.toArray(classes); client.startRetransformClasses(size); 注:class替换 inst.retransformClasses(classes); client.skipRetransforms(); } } client.getRuntime().send(new OkayCommand()); } catch (UnmodifiableClassException uce) { ... } } });
Tags:  遥远地方看一看 看一看世界的繁华 就独自看一看大海 看一看 btrace

延伸阅读

最新评论

发表评论