Skip to content

Commit

Permalink
Merge pull request #1813 from emeroad/#1811_bytecode_dump_option
Browse files Browse the repository at this point in the history
#1811 add bytecodedump option
Reviewed by jaehong-kim
  • Loading branch information
jaehong-kim committed May 27, 2016
2 parents f4731af + 825831e commit 1558f80
Show file tree
Hide file tree
Showing 11 changed files with 408 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ profiler.tcpdatasender.command.accept.enable=true
# Set max depth, if -1 is unlimited and min is 2.
profiler.callstack.max.depth=64

# weather or not to propagate exceptions occurred at interceptor
profiler.interceptor.exception.propagate=false

# java bytecode dump option
bytecode.dump.enable=false
#bytecode.dump.classlist=com.pinpoint.user.UserService,com.pinpoint.debug.TestClass,
bytecode.dump.classlist=
bytecode.dump.bytecode=false
bytecode.dump.verify=false
bytecode.dump.asm=false

###########################################################
# application type #
###########################################################
Expand Down
10 changes: 10 additions & 0 deletions agent/src/main/resources/pinpoint.config
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ profiler.callstack.max.depth=64

# weather or not to propagate exceptions occurred at interceptor
profiler.interceptor.exception.propagate=false

# bytecode dump option
# java bytecode debug option
bytecode.dump.enable=false
#bytecode.dump.classlist=com.naver.user.UserService
bytecode.dump.classlist=
bytecode.dump.bytecode=false
bytecode.dump.verify=false
bytecode.dump.asm=false

###########################################################
# application type #
###########################################################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ public class ProfilerLibClass implements LibClass {
"com.navercorp.pinpoint.profiler",
"com.navercorp.pinpoint.thrift",
"com.navercorp.pinpoint.rpc",
/**
* @deprecated javassist
*/
"javassist",
"org.objectweb.asm",
"org.slf4j",
"org.apache.thrift",
"org.jboss.netty",
Expand Down
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,12 @@
<version>2.2</version>
</dependency>

<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-debug-all</artifactId>
<version>5.1</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
Expand Down
6 changes: 4 additions & 2 deletions profiler/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,14 @@

<!-- [End] Compile Interceptors -->

<!-- 3.17.0 has been released. but upgrading may cause some problems because that has been compiled with jdk1.7
let's wait until release compiled with jdk1.6 -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-debug-all</artifactId>
</dependency>

<dependency>
<groupId>org.apache.thrift</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import com.navercorp.pinpoint.profiler.context.storage.BufferedStorageFactory;
import com.navercorp.pinpoint.profiler.context.storage.SpanStorageFactory;
import com.navercorp.pinpoint.profiler.context.storage.StorageFactory;
import com.navercorp.pinpoint.profiler.instrument.ASMBytecodeDumpService;
import com.navercorp.pinpoint.profiler.instrument.BytecodeDumpTransformer;
import com.navercorp.pinpoint.profiler.instrument.JavassistClassPool;
import com.navercorp.pinpoint.profiler.interceptor.registry.DefaultInterceptorRegistryBinder;
import com.navercorp.pinpoint.profiler.interceptor.registry.InterceptorRegistryBinder;
Expand All @@ -62,6 +64,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -176,7 +179,8 @@ public DefaultAgent(AgentOption agentOption, final InterceptorRegistryBinder int
this.classFileTransformer = new ClassFileTransformerDispatcher(this, pluginContexts);
this.dynamicTransformService = new DynamicTransformService(instrumentation, classFileTransformer);

instrumentation.addTransformer(this.classFileTransformer, true);
ClassFileTransformer wrappedTransformer = wrapClassFileTransformer(classFileTransformer);
instrumentation.addTransformer(wrappedTransformer, true);

String applicationServerTypeString = profilerConfig.getApplicationServerType();
ServiceType applicationServerType = this.serviceTypeRegistryService.findServiceTypeByName(applicationServerTypeString);
Expand Down Expand Up @@ -215,6 +219,15 @@ public DefaultAgent(AgentOption agentOption, final InterceptorRegistryBinder int
InterceptorInvokerHelper.setPropagateException(profilerConfig.isPropagateInterceptorException());
}

private ClassFileTransformer wrapClassFileTransformer(ClassFileTransformer classFileTransformerDispatcher) {
final boolean enableBytecodeDump = profilerConfig.readBoolean(ASMBytecodeDumpService.ENABLE_BYTECODE_DUMP, ASMBytecodeDumpService.ENABLE_BYTECODE_DUMP_DEFAULT_VALUE);
if (enableBytecodeDump) {
logger.info("wrapBytecodeDumpTransformer");
return BytecodeDumpTransformer.wrap(classFileTransformerDispatcher, profilerConfig);
}
return classFileTransformerDispatcher;
}

public String getBootstrapCoreJar() {
return agentOption.getBootStrapCoreJarPath();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.navercorp.pinpoint.profiler.instrument;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.util.ASMifier;
import org.objectweb.asm.util.CheckClassAdapter;
import org.objectweb.asm.util.Printer;
import org.objectweb.asm.util.Textifier;
import org.objectweb.asm.util.TraceClassVisitor;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
* @author Woonduk Kang(emeroad)
*/
public class ASMBytecodeDisassembler {

private final int cwFlag;
private final int crFlag;

public ASMBytecodeDisassembler() {
this(ClassReader.EXPAND_FRAMES, ClassWriter.COMPUTE_FRAMES);
}

public ASMBytecodeDisassembler(int crFlag, int cwFlag) {
this.cwFlag = cwFlag;
this.crFlag = crFlag;
}

public String dumpBytecode(final byte[] bytecode) {
if (bytecode == null) {
throw new NullPointerException("bytecode must not be null");
}

return writeBytecode(bytecode, new Textifier());
}


public String dumpASM(byte[] bytecode) {
if (bytecode == null) {
throw new NullPointerException("bytecode must not be null");
}

return writeBytecode(bytecode, new ASMifier());
}

private String writeBytecode(byte[] bytecode, Printer printer) {

final StringWriter out = new StringWriter();
final PrintWriter writer = new PrintWriter(out);

accept(bytecode, printer, writer);

return out.toString();
}

private void accept(byte[] bytecode, Printer printer, PrintWriter writer) {

final ClassReader cr = new ClassReader(bytecode);
final ClassWriter cw = new ClassWriter(this.cwFlag);
final TraceClassVisitor tcv = new TraceClassVisitor(cw, printer, writer);
cr.accept(tcv, this.crFlag);
}

public String dumpVerify(byte[] bytecode, ClassLoader classLoader) {
if (bytecode == null) {
throw new NullPointerException("bytecode must not be null");
}
if (classLoader == null) {
throw new NullPointerException("classLoader must not be null");
}

final StringWriter out = new StringWriter();
final PrintWriter writer = new PrintWriter(out);

final ClassReader cr = new ClassReader(bytecode);
CheckClassAdapter.verify(cr, classLoader, true, writer);

return out.toString();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package com.navercorp.pinpoint.profiler.instrument;

import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig;
import com.navercorp.pinpoint.bootstrap.util.StringUtils;
import com.navercorp.pinpoint.profiler.util.JavaAssistUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* @author Woonduk Kang(emeroad)
*/
public class ASMBytecodeDumpService implements BytecodeDumpService {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

public static final String ENABLE_BYTECODE_DUMP = "bytecode.dump.enable";
public static final boolean ENABLE_BYTECODE_DUMP_DEFAULT_VALUE = false;

public static final String BYTECODE_DUMP_BYTECODE = "bytecode.dump.bytecode";
public static final boolean BYTECODE_DUMP_BYTECODE_DEFAULT_VALUE = true;

public static final String BYTECODE_DUMP_VERIFY = "bytecode.dump.verify";
public static final boolean BYTECODE_DUMP_VERIFY_DEFAULT_VALUE = false;

public static final String BYTECODE_DUMP_ASM = "bytecode.dump.asm";
public static final boolean BYTECODE_DUMP_ASM_DEFAULT_VALUE = true;

public static final String DUMP_CLASS_LIST = "bytecode.dump.classlist";

private final boolean dumpBytecode;
private final boolean dumpVerify;
private final boolean dumpASM;
private final Set<String> dumpJvmClassNameSet;

private ASMBytecodeDisassembler disassembler = new ASMBytecodeDisassembler();

public ASMBytecodeDumpService(ProfilerConfig profilerConfig) {
if (profilerConfig == null) {
throw new NullPointerException("profilerConfig must not be null");
}

this.dumpBytecode = profilerConfig.readBoolean(BYTECODE_DUMP_BYTECODE, BYTECODE_DUMP_BYTECODE_DEFAULT_VALUE);
this.dumpVerify = profilerConfig.readBoolean(BYTECODE_DUMP_VERIFY, BYTECODE_DUMP_VERIFY_DEFAULT_VALUE);
this.dumpASM = profilerConfig.readBoolean(BYTECODE_DUMP_ASM, BYTECODE_DUMP_ASM_DEFAULT_VALUE);

this.dumpJvmClassNameSet = getClassName(profilerConfig);
}

private Set<String> getClassName(ProfilerConfig profilerConfig) {
final String classNameList = profilerConfig.readString(DUMP_CLASS_LIST, "");
if (classNameList.isEmpty()) {
return Collections.emptySet();
} else {
final List<String> classList = StringUtils.splitAndTrim(classNameList, ",");
final List<String> jvmClassList = javaNameToJvmName(classList);
return new HashSet<String>(jvmClassList);
}
}

public ASMBytecodeDumpService(boolean dumpBytecode, boolean dumpVerify, boolean dumpASM, List<String> classNameList) {
if (classNameList == null) {
throw new NullPointerException("classNameList must not be null");
}

this.dumpBytecode = dumpBytecode;
this.dumpVerify = dumpVerify;
this.dumpASM = dumpASM;

List<String> jvmClassNameList = javaNameToJvmName(classNameList);
this.dumpJvmClassNameSet = new HashSet<String>(jvmClassNameList);
}

private List<String> javaNameToJvmName(List<String> classNameList) {
List<String> jvmNameList = new ArrayList<String>(classNameList.size());

for (String className : classNameList) {
jvmNameList.add(JavaAssistUtils.javaNameToJvmName(className));
}
return jvmNameList;
}

@Override
public void dumpBytecode(String dumpMessage, final String jvmClassName, final byte[] bytes, ClassLoader classLoader) {
if (jvmClassName == null) {
throw new NullPointerException("jvmClassName must not be null");
}

if (!filterClassName(jvmClassName)) {
return;
}


if (dumpBytecode) {
final String dumpBytecode = this.disassembler.dumpBytecode(bytes);
logger.info("{} class:{} bytecode:{}", dumpMessage, jvmClassName, dumpBytecode);
}

if (dumpVerify) {
if (classLoader == null) {
logger.debug("classLoader is null, jvmClassName:{}", jvmClassName);
classLoader = ClassLoader.getSystemClassLoader();
}
final String dumpVerify = this.disassembler.dumpVerify(bytes, classLoader);
logger.info("{} class:{} verify:{}", dumpMessage, jvmClassName, dumpVerify);
}

if (dumpASM) {
final String dumpASM = this.disassembler.dumpASM(bytes);
logger.info("{} class:{} asm:{}", dumpMessage, jvmClassName, dumpASM);
}
}

private boolean filterClassName(String className) {
return this.dumpJvmClassNameSet.contains(className);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.navercorp.pinpoint.profiler.instrument;

/**
* @author Woonduk Kang(emeroad)
*/
public interface BytecodeDumpService {

void dumpBytecode(String dumpMessage, String jvmClassName, byte[] bytes, ClassLoader classLoader);
}

0 comments on commit 1558f80

Please sign in to comment.