Merge remote-tracking branch 'origin/master' into object-view-model

pull/1531/head
gongdewei 4 years ago
commit 226bdce059

@ -0,0 +1,55 @@
name: build vmtool
on: [push]
jobs:
linux:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'adopt'
- name: Build with Maven
run: ./mvnw package
- uses: actions/upload-artifact@v2
with:
name: lib
path: arthas-vmtool/target/lib*
mac:
runs-on: macos-10.15
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'adopt'
- name: Build with Maven
run: ./mvnw package
- uses: actions/upload-artifact@v2
with:
name: lib
path: arthas-vmtool/target/lib*
windows:
runs-on: windows-2016
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'adopt'
- name: Build with Maven
run: ./mvnw package
- uses: actions/upload-artifact@v2
with:
name: lib
path: arthas-vmtool/target/*.dll

@ -0,0 +1,67 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '31 4 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'java', 'javascript', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

@ -0,0 +1,34 @@
name: release
on:
push:
tags:
- "arthas-all-*"
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
java: [8]
steps:
- uses: actions/checkout@v2
- name: Setup java
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Build with Maven
run: mvn clean package -P full
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
packaging/target/*.zip
packaging/target/*.deb
packaging/target/*.rpm
tunnel-server/target/*fatjar.jar
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -0,0 +1,43 @@
name: JavaCI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
java: [7, 8, 9, 10, 11 ]
steps:
- uses: actions/checkout@v2
- name: Setup java
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Build with Maven
run: mvn clean package -P full
build_jdk_ge_12:
runs-on: ubuntu-latest
strategy:
matrix:
java: [12, 13, 14 ]
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 8
- name: save java8 home
run: |
export JAVA8_HOME=$JAVA_HOME && echo $JAVA8_HOME
echo "export JAVA8_HOME=$JAVA_HOME" > ~/.testenv
- name: Setup java
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Build with Maven
run: |
source ~/.testenv
mvn -Dmaven.compiler.fork=true -Dmaven.compiler.executable=$JAVA8_HOME/bin/javac -DJAVA8_HOME=$JAVA8_HOME clean package -P full

3
.gitignore vendored

@ -21,3 +21,6 @@ site/src/site/sphinx/en/_build
dependency-reduced-pom.xml dependency-reduced-pom.xml
pom.xml.versionsBackup pom.xml.versionsBackup
.pmd .pmd
**/.flattened-pom.xml
**/.idea/**
**/cmake-build-debug/**

@ -1,22 +1,18 @@
/* /*
Licensed to the Apache Software Foundation (ASF) under one * Copyright 2007-present the original author or authors.
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * Licensed under the Apache License, Version 2.0 (the "License");
regarding copyright ownership. The ASF licenses this file * you may not use this file except in compliance with the License.
to you under the Apache License, Version 2.0 (the * You may obtain a copy of the License at
"License"); you may not use this file except in compliance *
with the License. You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0
*
http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
Unless required by applicable law or agreed to in writing, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
software distributed under the License is distributed on an * See the License for the specific language governing permissions and
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * limitations under the License.
KIND, either express or implied. See the License for the */
specific language governing permissions and limitations
under the License.
*/
import java.net.*; import java.net.*;
import java.io.*; import java.io.*;
import java.nio.channels.*; import java.nio.channels.*;
@ -24,11 +20,12 @@ import java.util.Properties;
public class MavenWrapperDownloader { public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/** /**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/ */
private static final String DEFAULT_DOWNLOAD_URL = private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/** /**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
@ -76,13 +73,13 @@ public class MavenWrapperDownloader {
} }
} }
} }
System.out.println("- Downloading from: : " + url); System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) { if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) { if(!outputFile.getParentFile().mkdirs()) {
System.out.println( System.out.println(
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
} }
} }
System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
@ -98,6 +95,16 @@ public class MavenWrapperDownloader {
} }
private static void downloadFileFromURL(String urlString, File destination) throws Exception { private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString); URL website = new URL(urlString);
ReadableByteChannel rbc; ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream()); rbc = Channels.newChannel(website.openStream());

Binary file not shown.

@ -1 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

@ -58,7 +58,7 @@ deploy:
- "packaging/target/*.zip" - "packaging/target/*.zip"
- "packaging/target/*.deb" - "packaging/target/*.deb"
- "packaging/target/*.rpm" - "packaging/target/*.rpm"
- "tunnel-server/target/*.jar" - "tunnel-server/target/*fatjar.jar"
skip_cleanup: true skip_cleanup: true
on: on:
tags: true tags: true

@ -141,8 +141,7 @@ chmod +x /tmp/sphinx.osx-x86_64
* 修改`as.sh`里的版本,最后修改日期, `Bootstrap.java`里的版本Dockerfile里的版本 * 修改`as.sh`里的版本,最后修改日期, `Bootstrap.java`里的版本Dockerfile里的版本
* 修改本地的maven settings.xml * 修改本地的maven settings.xml
* mvn release:prepare -Darguments="-DskipTests -P full" * mvn clean deploy -DskipTests -P full -P release
* mvn release:perform -Darguments="-DskipTests -P full"
如果在下载 sphinx-binary 出错,参考上面的 全量打包 的说明。 如果在下载 sphinx-binary 出错,参考上面的 全量打包 的说明。
@ -152,7 +151,8 @@ chmod +x /tmp/sphinx.osx-x86_64
比如下载地址: https://maven.aliyun.com/repository/public/com/taobao/arthas/arthas-packaging/3.x.x/arthas-packaging-3.x.x-bin.zip 比如下载地址: https://maven.aliyun.com/repository/public/com/taobao/arthas/arthas-packaging/3.x.x/arthas-packaging-3.x.x-bin.zip
* 需要更新 gh-pages 分支下面的 arthas-boot.jar/arthas-demo.jar/as.sh ,下载 doc.zip解压覆盖掉文档的更新 * 打上tagpush tag到仓库上
* 需要更新 gh-pages 分支下面的 arthas-boot.jar/math-game.jar/as.sh ,下载 doc.zip解压覆盖掉文档的更新
* 需要更新docker镜像push新的taghttps://hub.docker.com/r/hengyunabc/arthas/tags?page=1&ordering=last_updated * 需要更新docker镜像push新的taghttps://hub.docker.com/r/hengyunabc/arthas/tags?page=1&ordering=last_updated
以 3.1.0 版本为例: 以 3.1.0 版本为例:

@ -1,6 +1,6 @@
FROM openjdk:8-jdk-alpine FROM openjdk:8-jdk-alpine
ARG ARTHAS_VERSION="3.4.3" ARG ARTHAS_VERSION="3.5.2"
ARG MIRROR=false ARG MIRROR=false
ENV MAVEN_HOST=https://repo1.maven.org/maven2 \ ENV MAVEN_HOST=https://repo1.maven.org/maven2 \

@ -1,6 +1,6 @@
FROM alpine FROM alpine
ARG ARTHAS_VERSION="3.4.3" ARG ARTHAS_VERSION="3.5.2"
ARG MIRROR=false ARG MIRROR=false
ENV MAVEN_HOST=https://repo1.maven.org/maven2 \ ENV MAVEN_HOST=https://repo1.maven.org/maven2 \

@ -38,6 +38,7 @@ Arthas was built to solve these issues. A developer can troubleshoot your produc
* Supports command line interactive mode, with auto-complete feature enabled. * Supports command line interactive mode, with auto-complete feature enabled.
* Supports telnet and websocket, which enables both local and remote diagnostics with command line and browsers. * Supports telnet and websocket, which enables both local and remote diagnostics with command line and browsers.
* Supports profiler/Flame Graph * Supports profiler/Flame Graph
* Support get objects in the heap that are instances of the specified class.
* Supports JDK 6+. * Supports JDK 6+.
* Supports Linux/Mac/Windows. * Supports Linux/Mac/Windows.
@ -89,7 +90,7 @@ You can enter its interactive interface by executing `as.sh`, or execute `as.sh
* [Docker](https://arthas.aliyun.com/doc/en/docker.html) * [Docker](https://arthas.aliyun.com/doc/en/docker.html)
* [Arthas Spring Boot Starter](https://arthas.aliyun.com/doc/en/spring-boot-starter.html) * [Arthas Spring Boot Starter](https://arthas.aliyun.com/doc/en/spring-boot-starter.html)
* [User cases](https://github.com/alibaba/arthas/issues?q=label%3Auser-case) * [User cases](https://github.com/alibaba/arthas/issues?q=label%3Auser-case)
* [Questions and answers](https://github.com/alibaba/arthas/issues?utf8=%E2%9C%93&q=label%3Aquestion-answered+) * [FAQ](https://arthas.aliyun.com/doc/en/faq)
* [Compile and debug/How to contribute](https://github.com/alibaba/arthas/blob/master/CONTRIBUTING.md) * [Compile and debug/How to contribute](https://github.com/alibaba/arthas/blob/master/CONTRIBUTING.md)
* [Release Notes](https://github.com/alibaba/arthas/releases) * [Release Notes](https://github.com/alibaba/arthas/releases)
@ -182,18 +183,18 @@ public interface Servlet {
Memory compiler, compiles `.java` files into `.class` files in memory. Memory compiler, compiles `.java` files into `.class` files in memory.
```bash ```bash
mc /tmp/Test.java $ mc /tmp/Test.java
``` ```
#### redefine #### retransform
* https://arthas.aliyun.com/doc/en/redefine * https://arthas.aliyun.com/doc/en/retransform
Load the external `*.class` files to re-define the loaded classes in JVM. Load the external `*.class` files to retransform/hotswap the loaded classes in JVM.
```bash ```bash
redefine /tmp/Test.class retransform /tmp/Test.class
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class retransform -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
``` ```
#### sc #### sc
@ -234,6 +235,29 @@ $ sc -d org.springframework.web.context.support.XmlWebApplicationContext
``` ```
#### vmtool
* https://arthas.aliyun.com/doc/en/vmtool
Get objects in the heap that are instances of the specified class.
```bash
$ vmtool --action getInstances --className java.lang.String --limit 10
@String[][
@String[com/taobao/arthas/core/shell/session/Session],
@String[com.taobao.arthas.core.shell.session.Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/],
@String[java/util/concurrent/ConcurrentHashMap$ValueIterator],
@String[java/util/concurrent/locks/LockSupport],
]
```
#### stack #### stack
* https://arthas.aliyun.com/doc/en/stack * https://arthas.aliyun.com/doc/en/stack
@ -392,130 +416,21 @@ View profiler results under arthas-output via browser:
### Known Users ### Known Users
Arthas has more than 120 registered users, [View All](USERS.md).
Welcome to register the company name in this issue: https://github.com/alibaba/arthas/issues/111 (in order of registration) Welcome to register the company name in this issue: https://github.com/alibaba/arthas/issues/111 (in order of registration)
![Alibaba](static/alibaba.png) ![Alibaba](static/alibaba.png)
![Alipay](static/alipay.png) ![Alipay](static/alipay.png)
![Aliyun](static/aliyun.png) ![Aliyun](static/aliyun.png)
![Taobao](static/taobao.png) ![Taobao](static/taobao.png)
![Tmall](static/tmall.png)
![微医](static/weiyi.png)
![卓越教育](static/zhuoyuejiaoyu.png)
![狐狸金服](static/hulijingfu.png)
![三体云](static/santiyun.png)
![证大文化](static/zhengdawenhua.png)
![连连支付](static/lianlianpay.png)
![Acmedcare+](static/acmedcare.png)
![好慷](static/homeking365_log.png)
![来电科技](static/laidian.png)
![四格互联](static/sigehulian.png)
![ICBC](static/icbc.png) ![ICBC](static/icbc.png)
![陆鹰](static/luying.png)
![玩友时代](static/wangyoushidai.png)
![她社区](static/tashequ.png)
![龙腾出行](static/longtengchuxing.png)
![foscam](static/foscam.png)
![二维火](static/2dfire.png)
![lanxum](static/lanxum_com.png)
![纳里健康](static/ngarihealth.png)
![掌门1对1](static/zhangmen.png)
![offcn](static/offcn.png)
![sia](static/sia.png)
![振安资产](static/zhenganzichang.png)
![菠萝](static/bolo.png)
![中通快递](static/zto.png)
![光点科技](static/guangdian.png)
![广州工程技术职业学院](static/gzvtc.jpg)
![mstar](static/mstar.png)
![xwbank](static/xwbank.png)
![imexue](static/imexue.png)
![keking](static/keking.png)
![secoo](static/secoo.jpg)
![viax](static/viax.png)
![yanedu](static/yanedu.png)
![duia](static/duia.png)
![哈啰出行](static/hellobike.png)
![hollycrm](static/hollycrm.png)
![citycloud](static/citycloud.jpg)
![yidianzixun](static/yidianzixun.png)
![神州租车](static/zuche.png)
![天眼查](static/tianyancha.png)
![商脉云](static/anjianyun.png)
![三新文化](static/sanxinbook.png)
![雪球财经](static/xueqiu.png) ![雪球财经](static/xueqiu.png)
![百安居](static/bthome.png)
![安心保险](static/95303.png)
![杭州源诚科技](static/hzyc.png)
![91moxie](static/91moxie.png)
![智慧开源](static/wisdom.png)
![富佳科技](static/fujias.png)
![鼎尖软件](static/dingjiansoft.png)
![广通软件](static/broada.png)
![九鼎瑞信](static/evercreative.jpg)
![小米有品](static/xiaomiyoupin.png)
![欧冶云商](static/ouyeel.png)
![投投科技](static/toutou.png)
![饿了么](static/ele.png)
![58同城](static/58.png)
![上海浪沙](static/runsa.png)
![符律科技](static/fhldtech.png)
![顺丰科技](static/sf.png) ![顺丰科技](static/sf.png)
![新致软件](static/newtouch.png)
![北京华宇信息](static/thunisoft.png)
![太平洋保险](static/cpic.png)
![旅享网络](static/risingch.png)
![水滴互联](static/shuidihuzhu.png)
![贝壳找房](static/ke.png) ![贝壳找房](static/ke.png)
![嘟嘟牛](static/dodonew.png)
![云幂信息](static/yunmixinxi.png)
![随手科技](static/sui.png)
![妈妈去哪儿](static/mamaqunaer.jpg)
![云实信息](static/realscloud.png)
![BBD数联铭品](static/bbdservice.png)
![伙伴集团](static/zhaoshang800.png)
![数梦工场](static/dtdream.png)
![安恒信息](static/dbappsecurity.png)
![亚信科技](static/asiainfo.png)
![云舒写](static/yunshuxie.png)
![微住](static/iweizhu.png)
![月亮小屋](static/bluemoon.png)
![大搜车](static/souche.png)
![今日图书](static/jinritushu.png)
![竹间智能](static/emotibot.png)
![数字认证](static/bjca.png)
![360金融](static/360jinrong.png)
![安居客](static/anjuke.jpg)
![qunar](static/qunar.png)
![ctrip](static/ctrip.png)
![Tuniu](static/tuniu.png)
![多点](static/dmall.jpg)
![转转](static/zhuanzhuan.jpg)
![金蝶](static/kingdee.jpg)
![华清飞扬](static/sincetimes.jpg)
![神奇视角](static/fasterar.jpg)
![南京昂克软件](static/angke.jpg)
![网盛生意宝](static/netsun.jpg)
![北京登云美业网络](static/idengyun.jpg)
![Holder](static/holder.png)
![立林科技](static/leelen.png)
![爱成长](static/aichengzhang.png)
![嘉云数据](static/clubfactory.png)
![百草味](static/bcw.png)
![青岛优米](static/youmi.png)
![紫光软件](static/unis.png)
![拓保软件](static/tobosoft.png)
![海信集团](static/hisense.png)
![小红唇](static/xiaohongchun.png)
![上海恺英](static/kaiying.png)
![上海慧力](static/xiaohuasheng.png)
![上海喔噻](static/shouqingba.png)
![vipkid](static/vipkid.png) ![vipkid](static/vipkid.png)
![宇中科技](static/yuzhong.png)
![蘑菇财富](static/mogu.jpg)
![喔趣科技](static/woqu.png)
![百度凤巢](static/baidufengchao.png) ![百度凤巢](static/baidufengchao.png)
![喜百年供应链科技](static/xbn.png) ![有赞](static/youzan.png)
![折耳根科技](static/zheergen.png)
### Derivative Projects ### Derivative Projects
@ -532,6 +447,7 @@ This project exists, thanks to all the people who contributed.
#### Projects #### Projects
* [bytekit](https://github.com/alibaba/bytekit) Java Bytecode Kit.
* [greys-anatomy](https://github.com/oldmanpushcart/greys-anatomy): The Arthas code base has derived from Greys, we thank for the excellent work done by Greys. * [greys-anatomy](https://github.com/oldmanpushcart/greys-anatomy): The Arthas code base has derived from Greys, we thank for the excellent work done by Greys.
* [termd](https://github.com/alibaba/termd): Arthas's terminal implementation is based on termd, an open source library for writing terminal applications in Java. * [termd](https://github.com/alibaba/termd): Arthas's terminal implementation is based on termd, an open source library for writing terminal applications in Java.
* [crash](https://github.com/crashub/crash): Arthas's text based user interface rendering is based on codes extracted from [here](https://github.com/crashub/crash/tree/1.3.2/shell) * [crash](https://github.com/crashub/crash): Arthas's text based user interface rendering is based on codes extracted from [here](https://github.com/crashub/crash/tree/1.3.2/shell)

@ -24,6 +24,7 @@ English version goes [here](README.md).
0. 是否有一个全局视角来查看系统的运行状况? 0. 是否有一个全局视角来查看系统的运行状况?
0. 有什么办法可以监控到JVM的实时运行状态 0. 有什么办法可以监控到JVM的实时运行状态
0. 怎么快速定位应用的热点,生成火焰图? 0. 怎么快速定位应用的热点,生成火焰图?
0. 怎样直接从JVM内查找某个类的实例
`Arthas`支持JDK 6+支持Linux/Mac/Windows采用命令行交互模式同时提供丰富的 `Tab` 自动补全功能,进一步方便进行问题的定位和诊断。 `Arthas`支持JDK 6+支持Linux/Mac/Windows采用命令行交互模式同时提供丰富的 `Tab` 自动补全功能,进一步方便进行问题的定位和诊断。
@ -78,7 +79,7 @@ curl -L https://arthas.aliyun.com/install.sh | sh
* [Docker](https://arthas.aliyun.com/doc/docker.html) * [Docker](https://arthas.aliyun.com/doc/docker.html)
* [Arthas Spring Boot Starter](https://arthas.aliyun.com/doc/spring-boot-starter.html) * [Arthas Spring Boot Starter](https://arthas.aliyun.com/doc/spring-boot-starter.html)
* [用户案例](https://github.com/alibaba/arthas/issues?q=label%3Auser-case) * [用户案例](https://github.com/alibaba/arthas/issues?q=label%3Auser-case)
* [常见问题](https://github.com/alibaba/arthas/issues?utf8=%E2%9C%93&q=label%3Aquestion-answered+) * [FAQ/常见问题](https://arthas.aliyun.com/doc/faq)
* [编译调试/参与贡献](https://github.com/alibaba/arthas/blob/master/CONTRIBUTING.md) * [编译调试/参与贡献](https://github.com/alibaba/arthas/blob/master/CONTRIBUTING.md)
* [Release Notes](https://github.com/alibaba/arthas/releases) * [Release Notes](https://github.com/alibaba/arthas/releases)
* [QQ群/钉钉群](https://arthas.aliyun.com/doc/contact-us.html) * [QQ群/钉钉群](https://arthas.aliyun.com/doc/contact-us.html)
@ -174,14 +175,14 @@ Memory Compiler/内存编译器,编译`.java`文件生成`.class`。
mc /tmp/Test.java mc /tmp/Test.java
``` ```
#### redefine #### retransform
* https://arthas.aliyun.com/doc/redefine * https://arthas.aliyun.com/doc/retransform
加载外部的`.class`文件redefine jvm已加载的类。 加载外部的`.class`文件retransform 热更新jvm已加载的类。
```bash ```bash
redefine /tmp/Test.class retransform /tmp/Test.class
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class retransform -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
``` ```
#### sc #### sc
@ -221,6 +222,27 @@ $ sc -d org.springframework.web.context.support.XmlWebApplicationContext
``` ```
#### vmtool
* https://arthas.aliyun.com/doc/vmtool
从JVM heap中获取指定类的实例。
```bash
$ vmtool --action getInstances --className java.lang.String --limit 10
@String[][
@String[com/taobao/arthas/core/shell/session/Session],
@String[com.taobao.arthas.core.shell.session.Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/],
@String[java/util/concurrent/ConcurrentHashMap$ValueIterator],
@String[java/util/concurrent/locks/LockSupport],
]
```
#### stack #### stack
* https://arthas.aliyun.com/doc/stack * https://arthas.aliyun.com/doc/stack
@ -381,132 +403,24 @@ OK
### Known Users ### Known Users
Arthas有超过120家登记用户[查看全部](USERS.md)。
如果您在使用Arthas请让我们知道您的使用对我们非常重要https://github.com/alibaba/arthas/issues/111 (按登记顺序排列) 如果您在使用Arthas请让我们知道您的使用对我们非常重要https://github.com/alibaba/arthas/issues/111 (按登记顺序排列)
![Alibaba](static/alibaba.png) ![Alibaba](static/alibaba.png)
![Alipay](static/alipay.png) ![Alipay](static/alipay.png)
![Aliyun](static/aliyun.png) ![Aliyun](static/aliyun.png)
![Taobao](static/taobao.png) ![Taobao](static/taobao.png)
![Tmall](static/tmall.png)
![微医](static/weiyi.png)
![卓越教育](static/zhuoyuejiaoyu.png)
![狐狸金服](static/hulijingfu.png)
![三体云](static/santiyun.png)
![证大文化](static/zhengdawenhua.png)
![连连支付](static/lianlianpay.png)
![Acmedcare+](static/acmedcare.png)
![好慷](static/homeking365_log.png)
![来电科技](static/laidian.png)
![四格互联](static/sigehulian.png)
![ICBC](static/icbc.png) ![ICBC](static/icbc.png)
![陆鹰](static/luying.png)
![玩友时代](static/wangyoushidai.png)
![她社区](static/tashequ.png)
![龙腾出行](static/longtengchuxing.png)
![foscam](static/foscam.png)
![二维火](static/2dfire.png)
![lanxum](static/lanxum_com.png)
![纳里健康](static/ngarihealth.png)
![掌门1对1](static/zhangmen.png)
![offcn](static/offcn.png)
![sia](static/sia.png)
![振安资产](static/zhenganzichang.png)
![菠萝](static/bolo.png)
![中通快递](static/zto.png)
![光点科技](static/guangdian.png)
![广州工程技术职业学院](static/gzvtc.jpg)
![mstar](static/mstar.png)
![xwbank](static/xwbank.png)
![imexue](static/imexue.png)
![keking](static/keking.png)
![secoo](static/secoo.jpg)
![viax](static/viax.png)
![yanedu](static/yanedu.png)
![duia](static/duia.png)
![哈啰出行](static/hellobike.png)
![hollycrm](static/hollycrm.png)
![citycloud](static/citycloud.jpg)
![yidianzixun](static/yidianzixun.png)
![神州租车](static/zuche.png)
![天眼查](static/tianyancha.png)
![商脉云](static/anjianyun.png)
![三新文化](static/sanxinbook.png)
![雪球财经](static/xueqiu.png) ![雪球财经](static/xueqiu.png)
![百安居](static/bthome.png)
![安心保险](static/95303.png)
![杭州源诚科技](static/hzyc.png)
![91moxie](static/91moxie.png)
![智慧开源](static/wisdom.png)
![富佳科技](static/fujias.png)
![鼎尖软件](static/dingjiansoft.png)
![广通软件](static/broada.png)
![九鼎瑞信](static/evercreative.jpg)
![小米有品](static/xiaomiyoupin.png)
![欧冶云商](static/ouyeel.png)
![投投科技](static/toutou.png)
![饿了么](static/ele.png)
![58同城](static/58.png)
![上海浪沙](static/runsa.png)
![符律科技](static/fhldtech.png)
![顺丰科技](static/sf.png) ![顺丰科技](static/sf.png)
![新致软件](static/newtouch.png)
![北京华宇信息](static/thunisoft.png)
![太平洋保险](static/cpic.png)
![旅享网络](static/risingch.png)
![水滴互联](static/shuidihuzhu.png)
![贝壳找房](static/ke.png) ![贝壳找房](static/ke.png)
![嘟嘟牛](static/dodonew.png)
![云幂信息](static/yunmixinxi.png)
![随手科技](static/sui.png)
![妈妈去哪儿](static/mamaqunaer.jpg)
![云实信息](static/realscloud.png)
![BBD数联铭品](static/bbdservice.png)
![伙伴集团](static/zhaoshang800.png)
![数梦工场](static/dtdream.png)
![安恒信息](static/dbappsecurity.png)
![亚信科技](static/asiainfo.png)
![云舒写](static/yunshuxie.png)
![微住](static/iweizhu.png)
![月亮小屋](static/bluemoon.png)
![大搜车](static/souche.png)
![今日图书](static/jinritushu.png)
![竹间智能](static/emotibot.png)
![数字认证](static/bjca.png)
![360金融](static/360jinrong.png)
![安居客](static/anjuke.jpg)
![qunar](static/qunar.png)
![ctrip](static/ctrip.png)
![途牛](static/tuniu.png)
![多点](static/dmall.jpg)
![转转](static/zhuanzhuan.jpg)
![金蝶](static/kingdee.jpg)
![华清飞扬](static/sincetimes.jpg)
![神奇视角](static/fasterar.jpg)
![南京昂克软件](static/angke.jpg)
![网盛生意宝](static/netsun.jpg)
![北京登云美业网络](static/idengyun.jpg)
![Holder](static/holder.png)
![立林科技](static/leelen.png)
![爱成长](static/aichengzhang.png)
![嘉云数据](static/clubfactory.png)
![百草味](static/bcw.png)
![青岛优米](static/youmi.png)
![紫光软件](static/unis.png)
![拓保软件](static/tobosoft.png)
![海信集团](static/hisense.png)
![小红唇](static/xiaohongchun.png)
![上海恺英](static/kaiying.png)
![上海慧力](static/xiaohuasheng.png)
![上海喔噻](static/shouqingba.png)
![vipkid](static/vipkid.png) ![vipkid](static/vipkid.png)
![宇中科技](static/yuzhong.png)
![蘑菇财富](static/mogu.jpg)
![喔趣科技](static/woqu.png)
![百度凤巢](static/baidufengchao.png) ![百度凤巢](static/baidufengchao.png)
![喜百年供应链科技](static/xbn.png) ![有赞](static/youzan.png)
![折耳根科技](static/zheergen.png)
### 生项目 ### 衍生项目
* [Bistoury: 一个集成了Arthas的项目](https://github.com/qunarcorp/bistoury) * [Bistoury: 一个集成了Arthas的项目](https://github.com/qunarcorp/bistoury)
* [一个使用MVEL脚本的fork](https://github.com/XhinLiang/arthas) * [一个使用MVEL脚本的fork](https://github.com/XhinLiang/arthas)
@ -522,6 +436,7 @@ OK
#### Projects #### Projects
* [bytekit](https://github.com/alibaba/bytekit) Java Bytecode KitArthas里字节码增强的内核。
* [greys-anatomy](https://github.com/oldmanpushcart/greys-anatomy): Arthas代码基于Greys二次开发而来非常感谢Greys之前所有的工作以及Greys原作者对Arthas提出的意见和建议 * [greys-anatomy](https://github.com/oldmanpushcart/greys-anatomy): Arthas代码基于Greys二次开发而来非常感谢Greys之前所有的工作以及Greys原作者对Arthas提出的意见和建议
* [termd](https://github.com/alibaba/termd): Arthas的命令行实现基于termd开发是一款优秀的命令行程序开发框架感谢termd提供了优秀的框架。 * [termd](https://github.com/alibaba/termd): Arthas的命令行实现基于termd开发是一款优秀的命令行程序开发框架感谢termd提供了优秀的框架。
* [crash](https://github.com/crashub/crash): Arthas的文本渲染功能基于crash中的文本渲染功能开发可以从[这里](https://github.com/crashub/crash/tree/1.3.2/shell)看到源码感谢crash在这方面所做的优秀工作。 * [crash](https://github.com/crashub/crash): Arthas的文本渲染功能基于crash中的文本渲染功能开发可以从[这里](https://github.com/crashub/crash/tree/1.3.2/shell)看到源码感谢crash在这方面所做的优秀工作。

@ -0,0 +1,157 @@
### Known Users
Welcome to register the company name in this issue: https://github.com/alibaba/arthas/issues/111 (in order of registration)
![Alibaba](static/alibaba.png)
![Alipay](static/alipay.png)
![Aliyun](static/aliyun.png)
![Taobao](static/taobao.png)
![Tmall](static/tmall.png)
![微医](static/weiyi.png)
![卓越教育](static/zhuoyuejiaoyu.png)
![狐狸金服](static/hulijingfu.png)
![三体云](static/santiyun.png)
![证大文化](static/zhengdawenhua.png)
![连连支付](static/lianlianpay.png)
![Acmedcare+](static/acmedcare.png)
![好慷](static/homeking365_log.png)
![来电科技](static/laidian.png)
![四格互联](static/sigehulian.png)
![ICBC](static/icbc.png)
![陆鹰](static/luying.png)
![玩友时代](static/wangyoushidai.png)
![她社区](static/tashequ.png)
![龙腾出行](static/longtengchuxing.png)
![foscam](static/foscam.png)
![二维火](static/2dfire.png)
![lanxum](static/lanxum_com.png)
![纳里健康](static/ngarihealth.png)
![掌门1对1](static/zhangmen.png)
![offcn](static/offcn.png)
![sia](static/sia.png)
![振安资产](static/zhenganzichang.png)
![菠萝](static/bolo.png)
![中通快递](static/zto.png)
![光点科技](static/guangdian.png)
![广州工程技术职业学院](static/gzvtc.jpg)
![mstar](static/mstar.png)
![xwbank](static/xwbank.png)
![imexue](static/imexue.png)
![keking](static/keking.png)
![secoo](static/secoo.jpg)
![viax](static/viax.png)
![yanedu](static/yanedu.png)
![duia](static/duia.png)
![哈啰出行](static/hellobike.png)
![hollycrm](static/hollycrm.png)
![citycloud](static/citycloud.jpg)
![yidianzixun](static/yidianzixun.png)
![神州租车](static/zuche.png)
![天眼查](static/tianyancha.png)
![商脉云](static/anjianyun.png)
![三新文化](static/sanxinbook.png)
![雪球财经](static/xueqiu.png)
![百安居](static/bthome.png)
![安心保险](static/95303.png)
![杭州源诚科技](static/hzyc.png)
![91moxie](static/91moxie.png)
![智慧开源](static/wisdom.png)
![富佳科技](static/fujias.png)
![鼎尖软件](static/dingjiansoft.png)
![广通软件](static/broada.png)
![九鼎瑞信](static/evercreative.jpg)
![小米有品](static/xiaomiyoupin.png)
![欧冶云商](static/ouyeel.png)
![投投科技](static/toutou.png)
![饿了么](static/ele.png)
![58同城](static/58.png)
![上海浪沙](static/runsa.png)
![符律科技](static/fhldtech.png)
![顺丰科技](static/sf.png)
![新致软件](static/newtouch.png)
![北京华宇信息](static/thunisoft.png)
![太平洋保险](static/cpic.png)
![旅享网络](static/risingch.png)
![水滴互联](static/shuidihuzhu.png)
![贝壳找房](static/ke.png)
![嘟嘟牛](static/dodonew.png)
![云幂信息](static/yunmixinxi.png)
![随手科技](static/sui.png)
![妈妈去哪儿](static/mamaqunaer.jpg)
![云实信息](static/realscloud.png)
![BBD数联铭品](static/bbdservice.png)
![伙伴集团](static/zhaoshang800.png)
![数梦工场](static/dtdream.png)
![安恒信息](static/dbappsecurity.png)
![亚信科技](static/asiainfo.png)
![云舒写](static/yunshuxie.png)
![微住](static/iweizhu.png)
![月亮小屋](static/bluemoon.png)
![大搜车](static/souche.png)
![今日图书](static/jinritushu.png)
![竹间智能](static/emotibot.png)
![数字认证](static/bjca.png)
![360金融](static/360jinrong.png)
![安居客](static/anjuke.jpg)
![qunar](static/qunar.png)
![ctrip](static/ctrip.png)
![Tuniu](static/tuniu.png)
![多点](static/dmall.jpg)
![转转](static/zhuanzhuan.jpg)
![金蝶](static/kingdee.jpg)
![华清飞扬](static/sincetimes.jpg)
![神奇视角](static/fasterar.jpg)
![南京昂克软件](static/angke.jpg)
![网盛生意宝](static/netsun.jpg)
![北京登云美业网络](static/idengyun.jpg)
![Holder](static/holder.png)
![立林科技](static/leelen.png)
![爱成长](static/aichengzhang.png)
![嘉云数据](static/clubfactory.png)
![百草味](static/bcw.png)
![青岛优米](static/youmi.png)
![紫光软件](static/unis.png)
![拓保软件](static/tobosoft.png)
![海信集团](static/hisense.png)
![小红唇](static/xiaohongchun.png)
![上海恺英](static/kaiying.png)
![上海慧力](static/xiaohuasheng.png)
![上海喔噻](static/shouqingba.png)
![vipkid](static/vipkid.png)
![宇中科技](static/yuzhong.png)
![蘑菇财富](static/mogu.jpg)
![喔趣科技](static/woqu.png)
![百度凤巢](static/baidufengchao.png)
![喜百年供应链科技](static/xbn.png)
![折耳根科技](static/zheergen.png)
![qdama](static/qdm_logo.png)
![有赞](static/youzan.png)
![中原银行](static/zhongyuanbank.png)
![CVTE](static/cvte.png)
* 网易云
* 派迩信息技术
* 朴新教育
* OK智慧教育
* 云集
* 业余草科技
* 家家顺
* 兰亮
* 浪潮集团
* 福建博思软件
* OPPO
* 中科软科技
* 大搜车
* 泰豪软件
* 中房
* 安恒信息
* 武汉力龙
* 埃欧体科技
* 创维
* 启迪出行
* 大华股份
* 黄豆伟业
* 中国有赞
* 车巴达
* 华为
* 云管书

@ -1,10 +1,10 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.taobao.arthas</groupId> <groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId> <artifactId>arthas-all</artifactId>
<version>3.4.4-SNAPSHOT</version> <version>${revision}</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<artifactId>arthas-agent</artifactId> <artifactId>arthas-agent</artifactId>

@ -1,10 +1,10 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.taobao.arthas</groupId> <groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId> <artifactId>arthas-all</artifactId>
<version>3.4.4-SNAPSHOT</version> <version>${revision}</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<artifactId>arthas-agent-attach</artifactId> <artifactId>arthas-agent-attach</artifactId>
@ -21,8 +21,6 @@
<dependency> <dependency>
<groupId>net.bytebuddy</groupId> <groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId> <artifactId>byte-buddy-agent</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.zeroturnaround</groupId> <groupId>org.zeroturnaround</groupId>

@ -45,7 +45,10 @@ public class ArthasAgent {
public ArthasAgent(Map<String, String> configMap, String arthasHome, boolean slientInit, public ArthasAgent(Map<String, String> configMap, String arthasHome, boolean slientInit,
Instrumentation instrumentation) { Instrumentation instrumentation) {
this.configMap = configMap; if (configMap != null) {
this.configMap = configMap;
}
this.arthasHome = arthasHome; this.arthasHome = arthasHome;
this.slientInit = slientInit; this.slientInit = slientInit;
this.instrumentation = instrumentation; this.instrumentation = instrumentation;

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.taobao.arthas</groupId> <groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId> <artifactId>arthas-all</artifactId>
<version>3.4.4-SNAPSHOT</version> <version>${revision}</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
@ -39,17 +39,6 @@
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
</dependency>
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-zip</artifactId>
<type>jar</type>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>

@ -12,6 +12,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.core.env.ConfigurableEnvironment;
import com.taobao.arthas.agent.attach.ArthasAgent; import com.taobao.arthas.agent.attach.ArthasAgent;
@ -25,6 +26,15 @@ import com.taobao.arthas.agent.attach.ArthasAgent;
public class ArthasConfiguration { public class ArthasConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ArthasConfiguration.class); private static final Logger logger = LoggerFactory.getLogger(ArthasConfiguration.class);
@Autowired
ConfigurableEnvironment environment;
/**
* <pre>
* 1. arthas.* Arthas
* 2. ArthasProperties
* </pre>
*/
@ConfigurationProperties(prefix = "arthas") @ConfigurationProperties(prefix = "arthas")
@ConditionalOnMissingBean @ConditionalOnMissingBean
@Bean @Bean
@ -36,7 +46,16 @@ public class ArthasConfiguration {
@Bean @Bean
public ArthasAgent arthasAgent(@Autowired Map<String, String> arthasConfigMap, public ArthasAgent arthasAgent(@Autowired Map<String, String> arthasConfigMap,
@Autowired ArthasProperties arthasProperties) throws Throwable { @Autowired ArthasProperties arthasProperties) throws Throwable {
arthasConfigMap = StringUtils.removeDashKey(arthasConfigMap); arthasConfigMap = StringUtils.removeDashKey(arthasConfigMap);
ArthasProperties.updateArthasConfigMapDefaultValue(arthasConfigMap);
/**
* @see org.springframework.boot.context.ContextIdApplicationContextInitializer#getApplicationId(ConfigurableEnvironment)
*/
String appName = environment.getProperty("spring.application.name");
if (arthasConfigMap.get("appName") == null && appName != null) {
arthasConfigMap.put("appName", appName);
}
// 给配置全加上前缀 // 给配置全加上前缀
Map<String, String> mapWithPrefix = new HashMap<String, String>(arthasConfigMap.size()); Map<String, String> mapWithPrefix = new HashMap<String, String>(arthasConfigMap.size());
for (Entry<String, String> entry : arthasConfigMap.entrySet()) { for (Entry<String, String> entry : arthasConfigMap.entrySet()) {

@ -1,5 +1,7 @@
package com.alibaba.arthas.spring; package com.alibaba.arthas.spring;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
@ -16,6 +18,8 @@ public class ArthasProperties {
private String tunnelServer; private String tunnelServer;
private String agentId; private String agentId;
private String appName;
/** /**
* report executed command * report executed command
*/ */
@ -32,6 +36,20 @@ public class ArthasProperties {
* when arthas agent init error will throw exception by default. * when arthas agent init error will throw exception by default.
*/ */
private boolean slientInit = false; private boolean slientInit = false;
/**
* disabled commandsdefault disable stop command
*/
private String disabledCommands;
private static final String DEFAULT_DISABLEDCOMMANDS = "stop";
/**
* arthasConfigMap
*/
public static void updateArthasConfigMapDefaultValue(Map<String, String> arthasConfigMap) {
if (!arthasConfigMap.containsKey("disabledCommands")) {
arthasConfigMap.put("disabledCommands", DEFAULT_DISABLEDCOMMANDS);
}
}
public String getHome() { public String getHome() {
return home; return home;
@ -105,4 +123,19 @@ public class ArthasProperties {
this.sessionTimeout = sessionTimeout; this.sessionTimeout = sessionTimeout;
} }
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getDisabledCommands() {
return disabledCommands;
}
public void setDisabledCommands(String disabledCommands) {
this.disabledCommands = disabledCommands;
}
} }

@ -0,0 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>arthas-all</artifactId>
<groupId>com.taobao.arthas</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>arthas-vmtool</artifactId>
<name>arthas-vmtool</name>
<profiles>
<!-- https://github.com/openjdk/jdk/blob/jdk-16%2B36/src/java.base/windows/native/libjava/java_props_md.c#L568 -->
<!-- macos -->
<profile>
<id>macos-amd64</id>
<activation>
<os>
<family>mac</family>
<arch>x86_64</arch>
</os>
</activation>
<properties>
<os_name>macos</os_name>
<os_arch_option>-m64</os_arch_option>
<lib_name>libArthasJniLibrary-x64.dylib</lib_name>
</properties>
</profile>
<!-- linux -->
<profile>
<id>linux-amd64</id>
<activation>
<os>
<name>linux</name>
<arch>amd64</arch>
</os>
</activation>
<properties>
<os_name>linux</os_name>
<os_arch_option>-m64</os_arch_option>
<lib_name>libArthasJniLibrary-x64.so</lib_name>
</properties>
</profile>
<!-- windows -->
<profile>
<id>windows-amd64</id>
<activation>
<os>
<family>windows</family>
<arch>amd64</arch>
</os>
</activation>
<properties>
<os_name>windows</os_name>
<os_arch_option>-m64</os_arch_option>
<lib_name>libArthasJniLibrary-x64.dll</lib_name>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>1.0-alpha-11</version>
<extensions>true</extensions>
<configuration>
<javahIncludes>
<javahInclude>
<className>arthas.VmTool</className>
</javahInclude>
</javahIncludes>
<jdkIncludePath>${project.basedir}/src/main/native/head</jdkIncludePath>
<javahOS>${os_name}</javahOS>
<sources>
<source>
<directory>src/main/native/src</directory>
<fileNames>
<fileName>jni-library.cpp</fileName>
</fileNames>
</source>
</sources>
<compilerProvider>generic-classic</compilerProvider>
<compilerExecutable>g++</compilerExecutable>
<compilerStartOptions>
<compilerStartOption>${os_arch_option}</compilerStartOption>
<compilerStartOption>-fpic</compilerStartOption>
<compilerStartOption>-shared</compilerStartOption>
<compilerStartOption>-o</compilerStartOption>
</compilerStartOptions>
<linkerOutputDirectory>target</linkerOutputDirectory>
<linkerExecutable>g++</linkerExecutable>
<linkerStartOptions>
<linkerStartOption>${os_arch_option}</linkerStartOption>
<linkerStartOption>-fpic</linkerStartOption>
<linkerStartOption>-shared</linkerStartOption>
<linkerStartOption>-o</linkerStartOption>
<!-- for windows #1833 -->
<linkerStartOption>-static-libstdc++</linkerStartOption>
<linkerStartOption>-static</linkerStartOption>
</linkerStartOptions>
<linkerEndOptions>
<linkerEndOption>-o ${project.build.directory}/${lib_name}</linkerEndOption>
</linkerEndOptions>
</configuration>
<executions>
<execution>
<id>javah</id>
<phase>compile</phase>
<goals>
<goal>javah</goal>
<goal>initialize</goal>
<goal>compile</goal>
<goal>link</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<!-- 请不要删除这里的maven-jar-plugin也不要升级它的版本否则很可能无法正常打包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>1.0-alpha-11</version>
<extensions>true</extensions>
<configuration>
<javahIncludes>
<javahInclude>
<className>arthas.VmTool</className>
</javahInclude>
</javahIncludes>
<jdkIncludePath>${project.basedir}/src/main/native/head</jdkIncludePath>
<javahOS>${os_name}</javahOS>
<sources>
<source>
<directory>src/main/native/src</directory>
<fileNames>
<fileName>jni-library.cpp</fileName>
</fileNames>
</source>
</sources>
<compilerProvider>generic-classic</compilerProvider>
<compilerExecutable>g++</compilerExecutable>
<compilerStartOptions>
<compilerStartOption>${os_arch_option}</compilerStartOption>
<compilerStartOption>-fpic</compilerStartOption>
<compilerStartOption>-shared</compilerStartOption>
<compilerStartOption>-o</compilerStartOption>
</compilerStartOptions>
<linkerOutputDirectory>target</linkerOutputDirectory>
<linkerExecutable>g++</linkerExecutable>
<linkerStartOptions>
<linkerStartOption>${os_arch_option}</linkerStartOption>
<linkerStartOption>-fpic</linkerStartOption>
<linkerStartOption>-shared</linkerStartOption>
<linkerStartOption>-o</linkerStartOption>
</linkerStartOptions>
<linkerEndOptions>
<linkerEndOption>-o ${project.build.directory}/${lib_name}</linkerEndOption>
</linkerEndOptions>
</configuration>
<executions>
<execution>
<id>javah</id>
<phase>compile</phase>
<goals>
<goal>javah</goal>
<goal>initialize</goal>
<goal>compile</goal>
<goal>link</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,106 @@
package arthas;
/**
* @author ZhangZiCheng 2021-02-12
* @author hengyunabc 2021-04-26
* @since 3.5.1
*/
public class VmTool implements VmToolMXBean {
/**
* jni-lib
*/
public final static String JNI_LIBRARY_NAME = "ArthasJniLibrary";
private static VmTool instance;
private VmTool() {
}
public static VmTool getInstance() {
return getInstance(null);
}
public static synchronized VmTool getInstance(String libPath) {
if (instance != null) {
return instance;
}
if (libPath == null) {
System.loadLibrary(JNI_LIBRARY_NAME);
} else {
System.load(libPath);
}
instance = new VmTool();
return instance;
}
private static synchronized native void forceGc0();
/**
* classjvm
*/
private static synchronized native <T> T[] getInstances0(Class<T> klass, int limit);
/**
* classjvmByte
*/
private static synchronized native long sumInstanceSize0(Class<?> klass);
/**
* Byte
*/
private static native long getInstanceSize0(Object instance);
/**
* classjvm
*/
private static synchronized native long countInstances0(Class<?> klass);
/**
*
* @param klass Class.class
* @return
*/
private static synchronized native Class<?>[] getAllLoadedClasses0(Class<?> klass);
@Override
public void forceGc() {
forceGc0();
}
@Override
public <T> T[] getInstances(Class<T> klass) {
return getInstances0(klass, -1);
}
@Override
public <T> T[] getInstances(Class<T> klass, int limit) {
if (limit == 0) {
throw new IllegalArgumentException("limit can not be 0");
}
return getInstances0(klass, limit);
}
@Override
public long sumInstanceSize(Class<?> klass) {
return sumInstanceSize0(klass);
}
@Override
public long getInstanceSize(Object instance) {
return getInstanceSize0(instance);
}
@Override
public long countInstances(Class<?> klass) {
return countInstances0(klass);
}
@Override
public Class<?>[] getAllLoadedClasses() {
return getAllLoadedClasses0(Class.class);
}
}

@ -0,0 +1,53 @@
package arthas;
/**
* VmTool interface for JMX server. How to register VmTool MBean:
*
* <pre>
* {@code
* ManagementFactory.getPlatformMBeanServer().registerMBean(
* VmTool.getInstance(),
* new ObjectName("arthas:type=VmTool")
* );
* }
* </pre>
* @author hengyunabc 2021-04-26
*/
public interface VmToolMXBean {
/**
* https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html#ForceGarbageCollection
*/
public void forceGc();
public <T> T[] getInstances(Class<T> klass);
/**
* classjvm
* @param <T>
* @param klass
* @param limit 0
* @return
*/
public <T> T[] getInstances(Class<T> klass, int limit);
/**
* classjvmByte
*/
public long sumInstanceSize(Class<?> klass);
/**
* Byte
*/
public long getInstanceSize(Object instance);
/**
* classjvm
*/
public long countInstances(Class<?> klass);
/**
*
*/
public Class<?>[] getAllLoadedClasses();
}

@ -0,0 +1,18 @@
cmake_minimum_required(VERSION 3.17)
project(arthas-native)
set(CMAKE_CXX_STANDARD 14)
add_library(jni-lib SHARED src/jni-library.cpp)
#使includejdk
include_directories("include")
include_directories(head)
IF (WIN32)
include_directories(head/windows)
ELSEIF (APPLE)
include_directories(head/macos)
ELSEIF (common/linux)
include_directories(head/linux)
ENDIF ()

@ -0,0 +1,560 @@
/*
* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#ifndef CLASSFILE_CONSTANTS_H
#define CLASSFILE_CONSTANTS_H
#ifdef __cplusplus
extern "C" {
#endif
/* Classfile version number for this information */
#define JVM_CLASSFILE_MAJOR_VERSION 52
#define JVM_CLASSFILE_MINOR_VERSION 0
/* Flags */
enum {
JVM_ACC_PUBLIC = 0x0001,
JVM_ACC_PRIVATE = 0x0002,
JVM_ACC_PROTECTED = 0x0004,
JVM_ACC_STATIC = 0x0008,
JVM_ACC_FINAL = 0x0010,
JVM_ACC_SYNCHRONIZED = 0x0020,
JVM_ACC_SUPER = 0x0020,
JVM_ACC_VOLATILE = 0x0040,
JVM_ACC_BRIDGE = 0x0040,
JVM_ACC_TRANSIENT = 0x0080,
JVM_ACC_VARARGS = 0x0080,
JVM_ACC_NATIVE = 0x0100,
JVM_ACC_INTERFACE = 0x0200,
JVM_ACC_ABSTRACT = 0x0400,
JVM_ACC_STRICT = 0x0800,
JVM_ACC_SYNTHETIC = 0x1000,
JVM_ACC_ANNOTATION = 0x2000,
JVM_ACC_ENUM = 0x4000
};
/* Used in newarray instruction. */
enum {
JVM_T_BOOLEAN = 4,
JVM_T_CHAR = 5,
JVM_T_FLOAT = 6,
JVM_T_DOUBLE = 7,
JVM_T_BYTE = 8,
JVM_T_SHORT = 9,
JVM_T_INT = 10,
JVM_T_LONG = 11
};
/* Constant Pool Entries */
enum {
JVM_CONSTANT_Utf8 = 1,
JVM_CONSTANT_Unicode = 2, /* unused */
JVM_CONSTANT_Integer = 3,
JVM_CONSTANT_Float = 4,
JVM_CONSTANT_Long = 5,
JVM_CONSTANT_Double = 6,
JVM_CONSTANT_Class = 7,
JVM_CONSTANT_String = 8,
JVM_CONSTANT_Fieldref = 9,
JVM_CONSTANT_Methodref = 10,
JVM_CONSTANT_InterfaceMethodref = 11,
JVM_CONSTANT_NameAndType = 12,
JVM_CONSTANT_MethodHandle = 15, // JSR 292
JVM_CONSTANT_MethodType = 16, // JSR 292
JVM_CONSTANT_InvokeDynamic = 18
};
/* JVM_CONSTANT_MethodHandle subtypes */
enum {
JVM_REF_getField = 1,
JVM_REF_getStatic = 2,
JVM_REF_putField = 3,
JVM_REF_putStatic = 4,
JVM_REF_invokeVirtual = 5,
JVM_REF_invokeStatic = 6,
JVM_REF_invokeSpecial = 7,
JVM_REF_newInvokeSpecial = 8,
JVM_REF_invokeInterface = 9
};
/* StackMapTable type item numbers */
enum {
JVM_ITEM_Top = 0,
JVM_ITEM_Integer = 1,
JVM_ITEM_Float = 2,
JVM_ITEM_Double = 3,
JVM_ITEM_Long = 4,
JVM_ITEM_Null = 5,
JVM_ITEM_UninitializedThis = 6,
JVM_ITEM_Object = 7,
JVM_ITEM_Uninitialized = 8
};
/* Type signatures */
enum {
JVM_SIGNATURE_ARRAY = '[',
JVM_SIGNATURE_BYTE = 'B',
JVM_SIGNATURE_CHAR = 'C',
JVM_SIGNATURE_CLASS = 'L',
JVM_SIGNATURE_ENDCLASS = ';',
JVM_SIGNATURE_ENUM = 'E',
JVM_SIGNATURE_FLOAT = 'F',
JVM_SIGNATURE_DOUBLE = 'D',
JVM_SIGNATURE_FUNC = '(',
JVM_SIGNATURE_ENDFUNC = ')',
JVM_SIGNATURE_INT = 'I',
JVM_SIGNATURE_LONG = 'J',
JVM_SIGNATURE_SHORT = 'S',
JVM_SIGNATURE_VOID = 'V',
JVM_SIGNATURE_BOOLEAN = 'Z'
};
/* Opcodes */
enum {
JVM_OPC_nop = 0,
JVM_OPC_aconst_null = 1,
JVM_OPC_iconst_m1 = 2,
JVM_OPC_iconst_0 = 3,
JVM_OPC_iconst_1 = 4,
JVM_OPC_iconst_2 = 5,
JVM_OPC_iconst_3 = 6,
JVM_OPC_iconst_4 = 7,
JVM_OPC_iconst_5 = 8,
JVM_OPC_lconst_0 = 9,
JVM_OPC_lconst_1 = 10,
JVM_OPC_fconst_0 = 11,
JVM_OPC_fconst_1 = 12,
JVM_OPC_fconst_2 = 13,
JVM_OPC_dconst_0 = 14,
JVM_OPC_dconst_1 = 15,
JVM_OPC_bipush = 16,
JVM_OPC_sipush = 17,
JVM_OPC_ldc = 18,
JVM_OPC_ldc_w = 19,
JVM_OPC_ldc2_w = 20,
JVM_OPC_iload = 21,
JVM_OPC_lload = 22,
JVM_OPC_fload = 23,
JVM_OPC_dload = 24,
JVM_OPC_aload = 25,
JVM_OPC_iload_0 = 26,
JVM_OPC_iload_1 = 27,
JVM_OPC_iload_2 = 28,
JVM_OPC_iload_3 = 29,
JVM_OPC_lload_0 = 30,
JVM_OPC_lload_1 = 31,
JVM_OPC_lload_2 = 32,
JVM_OPC_lload_3 = 33,
JVM_OPC_fload_0 = 34,
JVM_OPC_fload_1 = 35,
JVM_OPC_fload_2 = 36,
JVM_OPC_fload_3 = 37,
JVM_OPC_dload_0 = 38,
JVM_OPC_dload_1 = 39,
JVM_OPC_dload_2 = 40,
JVM_OPC_dload_3 = 41,
JVM_OPC_aload_0 = 42,
JVM_OPC_aload_1 = 43,
JVM_OPC_aload_2 = 44,
JVM_OPC_aload_3 = 45,
JVM_OPC_iaload = 46,
JVM_OPC_laload = 47,
JVM_OPC_faload = 48,
JVM_OPC_daload = 49,
JVM_OPC_aaload = 50,
JVM_OPC_baload = 51,
JVM_OPC_caload = 52,
JVM_OPC_saload = 53,
JVM_OPC_istore = 54,
JVM_OPC_lstore = 55,
JVM_OPC_fstore = 56,
JVM_OPC_dstore = 57,
JVM_OPC_astore = 58,
JVM_OPC_istore_0 = 59,
JVM_OPC_istore_1 = 60,
JVM_OPC_istore_2 = 61,
JVM_OPC_istore_3 = 62,
JVM_OPC_lstore_0 = 63,
JVM_OPC_lstore_1 = 64,
JVM_OPC_lstore_2 = 65,
JVM_OPC_lstore_3 = 66,
JVM_OPC_fstore_0 = 67,
JVM_OPC_fstore_1 = 68,
JVM_OPC_fstore_2 = 69,
JVM_OPC_fstore_3 = 70,
JVM_OPC_dstore_0 = 71,
JVM_OPC_dstore_1 = 72,
JVM_OPC_dstore_2 = 73,
JVM_OPC_dstore_3 = 74,
JVM_OPC_astore_0 = 75,
JVM_OPC_astore_1 = 76,
JVM_OPC_astore_2 = 77,
JVM_OPC_astore_3 = 78,
JVM_OPC_iastore = 79,
JVM_OPC_lastore = 80,
JVM_OPC_fastore = 81,
JVM_OPC_dastore = 82,
JVM_OPC_aastore = 83,
JVM_OPC_bastore = 84,
JVM_OPC_castore = 85,
JVM_OPC_sastore = 86,
JVM_OPC_pop = 87,
JVM_OPC_pop2 = 88,
JVM_OPC_dup = 89,
JVM_OPC_dup_x1 = 90,
JVM_OPC_dup_x2 = 91,
JVM_OPC_dup2 = 92,
JVM_OPC_dup2_x1 = 93,
JVM_OPC_dup2_x2 = 94,
JVM_OPC_swap = 95,
JVM_OPC_iadd = 96,
JVM_OPC_ladd = 97,
JVM_OPC_fadd = 98,
JVM_OPC_dadd = 99,
JVM_OPC_isub = 100,
JVM_OPC_lsub = 101,
JVM_OPC_fsub = 102,
JVM_OPC_dsub = 103,
JVM_OPC_imul = 104,
JVM_OPC_lmul = 105,
JVM_OPC_fmul = 106,
JVM_OPC_dmul = 107,
JVM_OPC_idiv = 108,
JVM_OPC_ldiv = 109,
JVM_OPC_fdiv = 110,
JVM_OPC_ddiv = 111,
JVM_OPC_irem = 112,
JVM_OPC_lrem = 113,
JVM_OPC_frem = 114,
JVM_OPC_drem = 115,
JVM_OPC_ineg = 116,
JVM_OPC_lneg = 117,
JVM_OPC_fneg = 118,
JVM_OPC_dneg = 119,
JVM_OPC_ishl = 120,
JVM_OPC_lshl = 121,
JVM_OPC_ishr = 122,
JVM_OPC_lshr = 123,
JVM_OPC_iushr = 124,
JVM_OPC_lushr = 125,
JVM_OPC_iand = 126,
JVM_OPC_land = 127,
JVM_OPC_ior = 128,
JVM_OPC_lor = 129,
JVM_OPC_ixor = 130,
JVM_OPC_lxor = 131,
JVM_OPC_iinc = 132,
JVM_OPC_i2l = 133,
JVM_OPC_i2f = 134,
JVM_OPC_i2d = 135,
JVM_OPC_l2i = 136,
JVM_OPC_l2f = 137,
JVM_OPC_l2d = 138,
JVM_OPC_f2i = 139,
JVM_OPC_f2l = 140,
JVM_OPC_f2d = 141,
JVM_OPC_d2i = 142,
JVM_OPC_d2l = 143,
JVM_OPC_d2f = 144,
JVM_OPC_i2b = 145,
JVM_OPC_i2c = 146,
JVM_OPC_i2s = 147,
JVM_OPC_lcmp = 148,
JVM_OPC_fcmpl = 149,
JVM_OPC_fcmpg = 150,
JVM_OPC_dcmpl = 151,
JVM_OPC_dcmpg = 152,
JVM_OPC_ifeq = 153,
JVM_OPC_ifne = 154,
JVM_OPC_iflt = 155,
JVM_OPC_ifge = 156,
JVM_OPC_ifgt = 157,
JVM_OPC_ifle = 158,
JVM_OPC_if_icmpeq = 159,
JVM_OPC_if_icmpne = 160,
JVM_OPC_if_icmplt = 161,
JVM_OPC_if_icmpge = 162,
JVM_OPC_if_icmpgt = 163,
JVM_OPC_if_icmple = 164,
JVM_OPC_if_acmpeq = 165,
JVM_OPC_if_acmpne = 166,
JVM_OPC_goto = 167,
JVM_OPC_jsr = 168,
JVM_OPC_ret = 169,
JVM_OPC_tableswitch = 170,
JVM_OPC_lookupswitch = 171,
JVM_OPC_ireturn = 172,
JVM_OPC_lreturn = 173,
JVM_OPC_freturn = 174,
JVM_OPC_dreturn = 175,
JVM_OPC_areturn = 176,
JVM_OPC_return = 177,
JVM_OPC_getstatic = 178,
JVM_OPC_putstatic = 179,
JVM_OPC_getfield = 180,
JVM_OPC_putfield = 181,
JVM_OPC_invokevirtual = 182,
JVM_OPC_invokespecial = 183,
JVM_OPC_invokestatic = 184,
JVM_OPC_invokeinterface = 185,
JVM_OPC_invokedynamic = 186,
JVM_OPC_new = 187,
JVM_OPC_newarray = 188,
JVM_OPC_anewarray = 189,
JVM_OPC_arraylength = 190,
JVM_OPC_athrow = 191,
JVM_OPC_checkcast = 192,
JVM_OPC_instanceof = 193,
JVM_OPC_monitorenter = 194,
JVM_OPC_monitorexit = 195,
JVM_OPC_wide = 196,
JVM_OPC_multianewarray = 197,
JVM_OPC_ifnull = 198,
JVM_OPC_ifnonnull = 199,
JVM_OPC_goto_w = 200,
JVM_OPC_jsr_w = 201,
JVM_OPC_MAX = 201
};
/* Opcode length initializer, use with something like:
* unsigned char opcode_length[JVM_OPC_MAX+1] = JVM_OPCODE_LENGTH_INITIALIZER;
*/
#define JVM_OPCODE_LENGTH_INITIALIZER { \
1, /* nop */ \
1, /* aconst_null */ \
1, /* iconst_m1 */ \
1, /* iconst_0 */ \
1, /* iconst_1 */ \
1, /* iconst_2 */ \
1, /* iconst_3 */ \
1, /* iconst_4 */ \
1, /* iconst_5 */ \
1, /* lconst_0 */ \
1, /* lconst_1 */ \
1, /* fconst_0 */ \
1, /* fconst_1 */ \
1, /* fconst_2 */ \
1, /* dconst_0 */ \
1, /* dconst_1 */ \
2, /* bipush */ \
3, /* sipush */ \
2, /* ldc */ \
3, /* ldc_w */ \
3, /* ldc2_w */ \
2, /* iload */ \
2, /* lload */ \
2, /* fload */ \
2, /* dload */ \
2, /* aload */ \
1, /* iload_0 */ \
1, /* iload_1 */ \
1, /* iload_2 */ \
1, /* iload_3 */ \
1, /* lload_0 */ \
1, /* lload_1 */ \
1, /* lload_2 */ \
1, /* lload_3 */ \
1, /* fload_0 */ \
1, /* fload_1 */ \
1, /* fload_2 */ \
1, /* fload_3 */ \
1, /* dload_0 */ \
1, /* dload_1 */ \
1, /* dload_2 */ \
1, /* dload_3 */ \
1, /* aload_0 */ \
1, /* aload_1 */ \
1, /* aload_2 */ \
1, /* aload_3 */ \
1, /* iaload */ \
1, /* laload */ \
1, /* faload */ \
1, /* daload */ \
1, /* aaload */ \
1, /* baload */ \
1, /* caload */ \
1, /* saload */ \
2, /* istore */ \
2, /* lstore */ \
2, /* fstore */ \
2, /* dstore */ \
2, /* astore */ \
1, /* istore_0 */ \
1, /* istore_1 */ \
1, /* istore_2 */ \
1, /* istore_3 */ \
1, /* lstore_0 */ \
1, /* lstore_1 */ \
1, /* lstore_2 */ \
1, /* lstore_3 */ \
1, /* fstore_0 */ \
1, /* fstore_1 */ \
1, /* fstore_2 */ \
1, /* fstore_3 */ \
1, /* dstore_0 */ \
1, /* dstore_1 */ \
1, /* dstore_2 */ \
1, /* dstore_3 */ \
1, /* astore_0 */ \
1, /* astore_1 */ \
1, /* astore_2 */ \
1, /* astore_3 */ \
1, /* iastore */ \
1, /* lastore */ \
1, /* fastore */ \
1, /* dastore */ \
1, /* aastore */ \
1, /* bastore */ \
1, /* castore */ \
1, /* sastore */ \
1, /* pop */ \
1, /* pop2 */ \
1, /* dup */ \
1, /* dup_x1 */ \
1, /* dup_x2 */ \
1, /* dup2 */ \
1, /* dup2_x1 */ \
1, /* dup2_x2 */ \
1, /* swap */ \
1, /* iadd */ \
1, /* ladd */ \
1, /* fadd */ \
1, /* dadd */ \
1, /* isub */ \
1, /* lsub */ \
1, /* fsub */ \
1, /* dsub */ \
1, /* imul */ \
1, /* lmul */ \
1, /* fmul */ \
1, /* dmul */ \
1, /* idiv */ \
1, /* ldiv */ \
1, /* fdiv */ \
1, /* ddiv */ \
1, /* irem */ \
1, /* lrem */ \
1, /* frem */ \
1, /* drem */ \
1, /* ineg */ \
1, /* lneg */ \
1, /* fneg */ \
1, /* dneg */ \
1, /* ishl */ \
1, /* lshl */ \
1, /* ishr */ \
1, /* lshr */ \
1, /* iushr */ \
1, /* lushr */ \
1, /* iand */ \
1, /* land */ \
1, /* ior */ \
1, /* lor */ \
1, /* ixor */ \
1, /* lxor */ \
3, /* iinc */ \
1, /* i2l */ \
1, /* i2f */ \
1, /* i2d */ \
1, /* l2i */ \
1, /* l2f */ \
1, /* l2d */ \
1, /* f2i */ \
1, /* f2l */ \
1, /* f2d */ \
1, /* d2i */ \
1, /* d2l */ \
1, /* d2f */ \
1, /* i2b */ \
1, /* i2c */ \
1, /* i2s */ \
1, /* lcmp */ \
1, /* fcmpl */ \
1, /* fcmpg */ \
1, /* dcmpl */ \
1, /* dcmpg */ \
3, /* ifeq */ \
3, /* ifne */ \
3, /* iflt */ \
3, /* ifge */ \
3, /* ifgt */ \
3, /* ifle */ \
3, /* if_icmpeq */ \
3, /* if_icmpne */ \
3, /* if_icmplt */ \
3, /* if_icmpge */ \
3, /* if_icmpgt */ \
3, /* if_icmple */ \
3, /* if_acmpeq */ \
3, /* if_acmpne */ \
3, /* goto */ \
3, /* jsr */ \
2, /* ret */ \
99, /* tableswitch */ \
99, /* lookupswitch */ \
1, /* ireturn */ \
1, /* lreturn */ \
1, /* freturn */ \
1, /* dreturn */ \
1, /* areturn */ \
1, /* return */ \
3, /* getstatic */ \
3, /* putstatic */ \
3, /* getfield */ \
3, /* putfield */ \
3, /* invokevirtual */ \
3, /* invokespecial */ \
3, /* invokestatic */ \
5, /* invokeinterface */ \
5, /* invokedynamic */ \
3, /* new */ \
2, /* newarray */ \
3, /* anewarray */ \
1, /* arraylength */ \
1, /* athrow */ \
3, /* checkcast */ \
3, /* instanceof */ \
1, /* monitorenter */ \
1, /* monitorexit */ \
0, /* wide */ \
4, /* multianewarray */ \
3, /* ifnull */ \
3, /* ifnonnull */ \
5, /* goto_w */ \
5 /* jsr_w */ \
}
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* CLASSFILE_CONSTANTS */

@ -0,0 +1,299 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#ifndef _JAVASOFT_JAWT_H_
#define _JAVASOFT_JAWT_H_
#include "jni.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* AWT native interface (new in JDK 1.3)
*
* The AWT native interface allows a native C or C++ application a means
* by which to access native structures in AWT. This is to facilitate moving
* legacy C and C++ applications to Java and to target the needs of the
* community who, at present, wish to do their own native rendering to canvases
* for performance reasons. Standard extensions such as Java3D also require a
* means to access the underlying native data structures of AWT.
*
* There may be future extensions to this API depending on demand.
*
* A VM does not have to implement this API in order to pass the JCK.
* It is recommended, however, that this API is implemented on VMs that support
* standard extensions, such as Java3D.
*
* Since this is a native API, any program which uses it cannot be considered
* 100% pure java.
*/
/*
* AWT Native Drawing Surface (JAWT_DrawingSurface).
*
* For each platform, there is a native drawing surface structure. This
* platform-specific structure can be found in jawt_md.h. It is recommended
* that additional platforms follow the same model. It is also recommended
* that VMs on Win32 and Solaris support the existing structures in jawt_md.h.
*
*******************
* EXAMPLE OF USAGE:
*******************
*
* In Win32, a programmer wishes to access the HWND of a canvas to perform
* native rendering into it. The programmer has declared the paint() method
* for their canvas subclass to be native:
*
*
* MyCanvas.java:
*
* import java.awt.*;
*
* public class MyCanvas extends Canvas {
*
* static {
* System.loadLibrary("mylib");
* }
*
* public native void paint(Graphics g);
* }
*
*
* myfile.c:
*
* #include "jawt_md.h"
* #include <assert.h>
*
* JNIEXPORT void JNICALL
* Java_MyCanvas_paint(JNIEnv* env, jobject canvas, jobject graphics)
* {
* JAWT awt;
* JAWT_DrawingSurface* ds;
* JAWT_DrawingSurfaceInfo* dsi;
* JAWT_Win32DrawingSurfaceInfo* dsi_win;
* jboolean result;
* jint lock;
*
* // Get the AWT
* awt.version = JAWT_VERSION_1_3;
* result = JAWT_GetAWT(env, &awt);
* assert(result != JNI_FALSE);
*
* // Get the drawing surface
* ds = awt.GetDrawingSurface(env, canvas);
* assert(ds != NULL);
*
* // Lock the drawing surface
* lock = ds->Lock(ds);
* assert((lock & JAWT_LOCK_ERROR) == 0);
*
* // Get the drawing surface info
* dsi = ds->GetDrawingSurfaceInfo(ds);
*
* // Get the platform-specific drawing info
* dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
*
* //////////////////////////////
* // !!! DO PAINTING HERE !!! //
* //////////////////////////////
*
* // Free the drawing surface info
* ds->FreeDrawingSurfaceInfo(dsi);
*
* // Unlock the drawing surface
* ds->Unlock(ds);
*
* // Free the drawing surface
* awt.FreeDrawingSurface(ds);
* }
*
*/
/*
* JAWT_Rectangle
* Structure for a native rectangle.
*/
typedef struct jawt_Rectangle {
jint x;
jint y;
jint width;
jint height;
} JAWT_Rectangle;
struct jawt_DrawingSurface;
/*
* JAWT_DrawingSurfaceInfo
* Structure for containing the underlying drawing information of a component.
*/
typedef struct jawt_DrawingSurfaceInfo {
/*
* Pointer to the platform-specific information. This can be safely
* cast to a JAWT_Win32DrawingSurfaceInfo on Windows or a
* JAWT_X11DrawingSurfaceInfo on Solaris. On Mac OS X this is a
* pointer to a NSObject that conforms to the JAWT_SurfaceLayers
* protocol. See jawt_md.h for details.
*/
void* platformInfo;
/* Cached pointer to the underlying drawing surface */
struct jawt_DrawingSurface* ds;
/* Bounding rectangle of the drawing surface */
JAWT_Rectangle bounds;
/* Number of rectangles in the clip */
jint clipSize;
/* Clip rectangle array */
JAWT_Rectangle* clip;
} JAWT_DrawingSurfaceInfo;
#define JAWT_LOCK_ERROR 0x00000001
#define JAWT_LOCK_CLIP_CHANGED 0x00000002
#define JAWT_LOCK_BOUNDS_CHANGED 0x00000004
#define JAWT_LOCK_SURFACE_CHANGED 0x00000008
/*
* JAWT_DrawingSurface
* Structure for containing the underlying drawing information of a component.
* All operations on a JAWT_DrawingSurface MUST be performed from the same
* thread as the call to GetDrawingSurface.
*/
typedef struct jawt_DrawingSurface {
/*
* Cached reference to the Java environment of the calling thread.
* If Lock(), Unlock(), GetDrawingSurfaceInfo() or
* FreeDrawingSurfaceInfo() are called from a different thread,
* this data member should be set before calling those functions.
*/
JNIEnv* env;
/* Cached reference to the target object */
jobject target;
/*
* Lock the surface of the target component for native rendering.
* When finished drawing, the surface must be unlocked with
* Unlock(). This function returns a bitmask with one or more of the
* following values:
*
* JAWT_LOCK_ERROR - When an error has occurred and the surface could not
* be locked.
*
* JAWT_LOCK_CLIP_CHANGED - When the clip region has changed.
*
* JAWT_LOCK_BOUNDS_CHANGED - When the bounds of the surface have changed.
*
* JAWT_LOCK_SURFACE_CHANGED - When the surface itself has changed
*/
jint (JNICALL *Lock)
(struct jawt_DrawingSurface* ds);
/*
* Get the drawing surface info.
* The value returned may be cached, but the values may change if
* additional calls to Lock() or Unlock() are made.
* Lock() must be called before this can return a valid value.
* Returns NULL if an error has occurred.
* When finished with the returned value, FreeDrawingSurfaceInfo must be
* called.
*/
JAWT_DrawingSurfaceInfo* (JNICALL *GetDrawingSurfaceInfo)
(struct jawt_DrawingSurface* ds);
/*
* Free the drawing surface info.
*/
void (JNICALL *FreeDrawingSurfaceInfo)
(JAWT_DrawingSurfaceInfo* dsi);
/*
* Unlock the drawing surface of the target component for native rendering.
*/
void (JNICALL *Unlock)
(struct jawt_DrawingSurface* ds);
} JAWT_DrawingSurface;
/*
* JAWT
* Structure for containing native AWT functions.
*/
typedef struct jawt {
/*
* Version of this structure. This must always be set before
* calling JAWT_GetAWT()
*/
jint version;
/*
* Return a drawing surface from a target jobject. This value
* may be cached.
* Returns NULL if an error has occurred.
* Target must be a java.awt.Component (should be a Canvas
* or Window for native rendering).
* FreeDrawingSurface() must be called when finished with the
* returned JAWT_DrawingSurface.
*/
JAWT_DrawingSurface* (JNICALL *GetDrawingSurface)
(JNIEnv* env, jobject target);
/*
* Free the drawing surface allocated in GetDrawingSurface.
*/
void (JNICALL *FreeDrawingSurface)
(JAWT_DrawingSurface* ds);
/*
* Since 1.4
* Locks the entire AWT for synchronization purposes
*/
void (JNICALL *Lock)(JNIEnv* env);
/*
* Since 1.4
* Unlocks the entire AWT for synchronization purposes
*/
void (JNICALL *Unlock)(JNIEnv* env);
/*
* Since 1.4
* Returns a reference to a java.awt.Component from a native
* platform handle. On Windows, this corresponds to an HWND;
* on Solaris and Linux, this is a Drawable. For other platforms,
* see the appropriate machine-dependent header file for a description.
* The reference returned by this function is a local
* reference that is only valid in this environment.
* This function returns a NULL reference if no component could be
* found with matching platform information.
*/
jobject (JNICALL *GetComponent)(JNIEnv* env, void* platformInfo);
} JAWT;
/*
* Get the AWT native structure. This function returns JNI_FALSE if
* an error occurs.
*/
_JNI_IMPORT_OR_EXPORT_
jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt);
#define JAWT_VERSION_1_3 0x00010003
#define JAWT_VERSION_1_4 0x00010004
#define JAWT_VERSION_1_7 0x00010007
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* !_JAVASOFT_JAWT_H_ */

@ -0,0 +1,259 @@
/*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
* Java Debug Wire Protocol Transport Service Provider Interface.
*/
#ifndef JDWPTRANSPORT_H
#define JDWPTRANSPORT_H
#include "jni.h"
enum {
JDWPTRANSPORT_VERSION_1_0 = 0x00010000
};
#ifdef __cplusplus
extern "C" {
#endif
struct jdwpTransportNativeInterface_;
struct _jdwpTransportEnv;
#ifdef __cplusplus
typedef _jdwpTransportEnv jdwpTransportEnv;
#else
typedef const struct jdwpTransportNativeInterface_ *jdwpTransportEnv;
#endif /* __cplusplus */
/*
* Errors. Universal errors with JVMTI/JVMDI equivalents keep the
* values the same.
*/
typedef enum {
JDWPTRANSPORT_ERROR_NONE = 0,
JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT = 103,
JDWPTRANSPORT_ERROR_OUT_OF_MEMORY = 110,
JDWPTRANSPORT_ERROR_INTERNAL = 113,
JDWPTRANSPORT_ERROR_ILLEGAL_STATE = 201,
JDWPTRANSPORT_ERROR_IO_ERROR = 202,
JDWPTRANSPORT_ERROR_TIMEOUT = 203,
JDWPTRANSPORT_ERROR_MSG_NOT_AVAILABLE = 204
} jdwpTransportError;
/*
* Structure to define capabilities
*/
typedef struct {
unsigned int can_timeout_attach :1;
unsigned int can_timeout_accept :1;
unsigned int can_timeout_handshake :1;
unsigned int reserved3 :1;
unsigned int reserved4 :1;
unsigned int reserved5 :1;
unsigned int reserved6 :1;
unsigned int reserved7 :1;
unsigned int reserved8 :1;
unsigned int reserved9 :1;
unsigned int reserved10 :1;
unsigned int reserved11 :1;
unsigned int reserved12 :1;
unsigned int reserved13 :1;
unsigned int reserved14 :1;
unsigned int reserved15 :1;
} JDWPTransportCapabilities;
/*
* Structures to define packet layout.
*
* See: http://java.sun.com/j2se/1.5/docs/guide/jpda/jdwp-spec.html
*/
enum {
/*
* If additional flags are added that apply to jdwpCmdPacket,
* then debugLoop.c: reader() will need to be updated to
* accept more than JDWPTRANSPORT_FLAGS_NONE.
*/
JDWPTRANSPORT_FLAGS_NONE = 0x0,
JDWPTRANSPORT_FLAGS_REPLY = 0x80
};
typedef struct {
jint len;
jint id;
jbyte flags;
jbyte cmdSet;
jbyte cmd;
jbyte *data;
} jdwpCmdPacket;
typedef struct {
jint len;
jint id;
jbyte flags;
jshort errorCode;
jbyte *data;
} jdwpReplyPacket;
typedef struct {
union {
jdwpCmdPacket cmd;
jdwpReplyPacket reply;
} type;
} jdwpPacket;
/*
* JDWP functions called by the transport.
*/
typedef struct jdwpTransportCallback {
void *(*alloc)(jint numBytes); /* Call this for all allocations */
void (*free)(void *buffer); /* Call this for all deallocations */
} jdwpTransportCallback;
typedef jint (JNICALL *jdwpTransport_OnLoad_t)(JavaVM *jvm,
jdwpTransportCallback *callback,
jint version,
jdwpTransportEnv** env);
/* Function Interface */
struct jdwpTransportNativeInterface_ {
/* 1 : RESERVED */
void *reserved1;
/* 2 : Get Capabilities */
jdwpTransportError (JNICALL *GetCapabilities)(jdwpTransportEnv* env,
JDWPTransportCapabilities *capabilities_ptr);
/* 3 : Attach */
jdwpTransportError (JNICALL *Attach)(jdwpTransportEnv* env,
const char* address,
jlong attach_timeout,
jlong handshake_timeout);
/* 4: StartListening */
jdwpTransportError (JNICALL *StartListening)(jdwpTransportEnv* env,
const char* address,
char** actual_address);
/* 5: StopListening */
jdwpTransportError (JNICALL *StopListening)(jdwpTransportEnv* env);
/* 6: Accept */
jdwpTransportError (JNICALL *Accept)(jdwpTransportEnv* env,
jlong accept_timeout,
jlong handshake_timeout);
/* 7: IsOpen */
jboolean (JNICALL *IsOpen)(jdwpTransportEnv* env);
/* 8: Close */
jdwpTransportError (JNICALL *Close)(jdwpTransportEnv* env);
/* 9: ReadPacket */
jdwpTransportError (JNICALL *ReadPacket)(jdwpTransportEnv* env,
jdwpPacket *pkt);
/* 10: Write Packet */
jdwpTransportError (JNICALL *WritePacket)(jdwpTransportEnv* env,
const jdwpPacket* pkt);
/* 11: GetLastError */
jdwpTransportError (JNICALL *GetLastError)(jdwpTransportEnv* env,
char** error);
};
/*
* Use inlined functions so that C++ code can use syntax such as
* env->Attach("mymachine:5000", 10*1000, 0);
*
* rather than using C's :-
*
* (*env)->Attach(env, "mymachine:5000", 10*1000, 0);
*/
struct _jdwpTransportEnv {
const struct jdwpTransportNativeInterface_ *functions;
#ifdef __cplusplus
jdwpTransportError GetCapabilities(JDWPTransportCapabilities *capabilities_ptr) {
return functions->GetCapabilities(this, capabilities_ptr);
}
jdwpTransportError Attach(const char* address, jlong attach_timeout,
jlong handshake_timeout) {
return functions->Attach(this, address, attach_timeout, handshake_timeout);
}
jdwpTransportError StartListening(const char* address,
char** actual_address) {
return functions->StartListening(this, address, actual_address);
}
jdwpTransportError StopListening(void) {
return functions->StopListening(this);
}
jdwpTransportError Accept(jlong accept_timeout, jlong handshake_timeout) {
return functions->Accept(this, accept_timeout, handshake_timeout);
}
jboolean IsOpen(void) {
return functions->IsOpen(this);
}
jdwpTransportError Close(void) {
return functions->Close(this);
}
jdwpTransportError ReadPacket(jdwpPacket *pkt) {
return functions->ReadPacket(this, pkt);
}
jdwpTransportError WritePacket(const jdwpPacket* pkt) {
return functions->WritePacket(this, pkt);
}
jdwpTransportError GetLastError(char** error) {
return functions->GetLastError(this, error);
}
#endif /* __cplusplus */
};
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* JDWPTRANSPORT_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,115 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
* This header file defines the data structures sent by the VM
* through the JVMTI CompiledMethodLoad callback function via the
* "void * compile_info" parameter. The memory pointed to by the
* compile_info parameter may not be referenced after returning from
* the CompiledMethodLoad callback. These are VM implementation
* specific data structures that may evolve in future releases. A
* JVMTI agent should interpret a non-NULL compile_info as a pointer
* to a region of memory containing a list of records. In a typical
* usage scenario, a JVMTI agent would cast each record to a
* jvmtiCompiledMethodLoadRecordHeader, a struct that represents
* arbitrary information. This struct contains a kind field to indicate
* the kind of information being passed, and a pointer to the next
* record. If the kind field indicates inlining information, then the
* agent would cast the record to a jvmtiCompiledMethodLoadInlineRecord.
* This record contains an array of PCStackInfo structs, which indicate
* for every pc address what are the methods on the invocation stack.
* The "methods" and "bcis" fields in each PCStackInfo struct specify a
* 1-1 mapping between these inlined methods and their bytecode indices.
* This can be used to derive the proper source lines of the inlined
* methods.
*/
#ifndef _JVMTI_CMLR_H_
#define _JVMTI_CMLR_H_
enum {
JVMTI_CMLR_MAJOR_VERSION_1 = 0x00000001,
JVMTI_CMLR_MINOR_VERSION_0 = 0x00000000,
JVMTI_CMLR_MAJOR_VERSION = 0x00000001,
JVMTI_CMLR_MINOR_VERSION = 0x00000000
/*
* This comment is for the "JDK import from HotSpot" sanity check:
* version: 1.0.0
*/
};
typedef enum {
JVMTI_CMLR_DUMMY = 1,
JVMTI_CMLR_INLINE_INFO = 2
} jvmtiCMLRKind;
/*
* Record that represents arbitrary information passed through JVMTI
* CompiledMethodLoadEvent void pointer.
*/
typedef struct _jvmtiCompiledMethodLoadRecordHeader {
jvmtiCMLRKind kind; /* id for the kind of info passed in the record */
jint majorinfoversion; /* major and minor info version values. Init'ed */
jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */
struct _jvmtiCompiledMethodLoadRecordHeader* next;
} jvmtiCompiledMethodLoadRecordHeader;
/*
* Record that gives information about the methods on the compile-time
* stack at a specific pc address of a compiled method. Each element in
* the methods array maps to same element in the bcis array.
*/
typedef struct _PCStackInfo {
void* pc; /* the pc address for this compiled method */
jint numstackframes; /* number of methods on the stack */
jmethodID* methods; /* array of numstackframes method ids */
jint* bcis; /* array of numstackframes bytecode indices */
} PCStackInfo;
/*
* Record that contains inlining information for each pc address of
* an nmethod.
*/
typedef struct _jvmtiCompiledMethodLoadInlineRecord {
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
jint numpcs; /* number of pc descriptors in this nmethod */
PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
} jvmtiCompiledMethodLoadInlineRecord;
/*
* Dummy record used to test that we can pass records with different
* information through the void pointer provided that they can be cast
* to a jvmtiCompiledMethodLoadRecordHeader.
*/
typedef struct _jvmtiCompiledMethodLoadDummyRecord {
jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
char message[50];
} jvmtiCompiledMethodLoadDummyRecord;
#endif

@ -0,0 +1,61 @@
/*
* Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#ifndef _JAVASOFT_JAWT_MD_H_
#define _JAVASOFT_JAWT_MD_H_
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Intrinsic.h>
#include "jawt.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* X11-specific declarations for AWT native interface.
* See notes in jawt.h for an example of use.
*/
typedef struct jawt_X11DrawingSurfaceInfo {
Drawable drawable;
Display* display;
VisualID visualID;
Colormap colormapID;
int depth;
/*
* Since 1.4
* Returns a pixel value from a set of RGB values.
* This is useful for paletted color (256 color) modes.
*/
int (JNICALL *GetAWTColor)(JAWT_DrawingSurface* ds,
int r, int g, int b);
} JAWT_X11DrawingSurfaceInfo;
#ifdef __cplusplus
}
#endif
#endif /* !_JAVASOFT_JAWT_MD_H_ */

@ -0,0 +1,51 @@
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility)
#define JNIEXPORT __attribute__((visibility("default")))
#define JNIIMPORT __attribute__((visibility("default")))
#else
#define JNIEXPORT
#define JNIIMPORT
#endif
#define JNICALL
typedef int jint;
#ifdef _LP64 /* 64-bit Solaris */
typedef long jlong;
#else
typedef long long jlong;
#endif
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */

@ -0,0 +1,77 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#ifndef _JAVASOFT_JAWT_MD_H_
#define _JAVASOFT_JAWT_MD_H_
#include "jawt.h"
#ifdef __OBJC__
#import <QuartzCore/CALayer.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*
* Mac OS X specific declarations for AWT native interface.
* See notes in jawt.h for an example of use.
*/
/*
* When calling JAWT_GetAWT with a JAWT version less than 1.7, you must pass this
* flag or you will not be able to get a valid drawing surface and JAWT_GetAWT will
* return false. This is to maintain compatibility with applications that used the
* interface with Java 6 which had multiple rendering models. This flag is not necessary
* when JAWT version 1.7 or greater is used as this is the only supported rendering mode.
*
* Example:
* JAWT awt;
* awt.version = JAWT_VERSION_1_4 | JAWT_MACOSX_USE_CALAYER;
* jboolean success = JAWT_GetAWT(env, &awt);
*/
#define JAWT_MACOSX_USE_CALAYER 0x80000000
/*
* When the native Cocoa toolkit is in use, the pointer stored in
* JAWT_DrawingSurfaceInfo->platformInfo points to a NSObject that conforms to the
* JAWT_SurfaceLayers protocol. Setting the layer property of this object will cause the
* specified layer to be overlaid on the Components rectangle. If the window the
* Component belongs to has a CALayer attached to it, this layer will be accessible via
* the windowLayer property.
*/
#ifdef __OBJC__
@protocol JAWT_SurfaceLayers
@property (readwrite, retain) CALayer *layer;
@property (readonly) CALayer *windowLayer;
@end
#endif
#ifdef __cplusplus
}
#endif
#endif /* !_JAVASOFT_JAWT_MD_H_ */

@ -0,0 +1,42 @@
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#define JNIEXPORT __attribute__((visibility("default")))
#define JNIIMPORT __attribute__((visibility("default")))
#define JNICALL
typedef int jint;
#ifdef _LP64 /* 64-bit */
typedef long jlong;
#else
typedef long long jlong;
#endif
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */

@ -0,0 +1,96 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
* AccessBridgeCallbacks.h 1.17 05/03/21
*/
/*
* Header file defining callback typedefs for Windows routines
* which are called from Java (responding to events, etc.).
*/
#ifndef __AccessBridgeCallbacks_H__
#define __AccessBridgeCallbacks_H__
#include <jni.h>
#include "AccessBridgePackages.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*AccessBridge_PropertyChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
wchar_t *property, wchar_t *oldValue, wchar_t *newValue);
typedef void (*AccessBridge_JavaShutdownFP) (long vmID);
typedef void (*AccessBridge_JavaShutdownFP) (long vmID);
typedef void (*AccessBridge_FocusGainedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_FocusLostFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_CaretUpdateFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_MouseClickedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_MouseEnteredFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_MouseExitedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_MousePressedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_MouseReleasedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_MenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_MenuDeselectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_MenuSelectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_PopupMenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_PopupMenuWillBecomeInvisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_PopupMenuWillBecomeVisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_PropertyNameChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
wchar_t *oldName, wchar_t *newName);
typedef void (*AccessBridge_PropertyDescriptionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
wchar_t *oldDescription, wchar_t *newDescription);
typedef void (*AccessBridge_PropertyStateChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
wchar_t *oldState, wchar_t *newState);
typedef void (*AccessBridge_PropertyValueChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
wchar_t *oldValue, wchar_t *newValue);
typedef void (*AccessBridge_PropertySelectionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_PropertyTextChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_PropertyCaretChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
int oldPosition, int newPosition);
typedef void (*AccessBridge_PropertyVisibleDataChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source);
typedef void (*AccessBridge_PropertyChildChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source,
JOBJECT64 oldChild, JOBJECT64 newChild);
typedef void (*AccessBridge_PropertyActiveDescendentChangeFP) (long vmID, JOBJECT64 event,
JOBJECT64 source,
JOBJECT64 oldActiveDescendent,
JOBJECT64 newActiveDescendent);
typedef void (*AccessBridge_PropertyTableModelChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 src,
wchar_t *oldValue, wchar_t *newValue);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,706 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/*
* Wrapper functions around calls to the AccessBridge DLL
*/
#include <windows.h>
#include <jni.h>
#include "AccessBridgeCallbacks.h"
#include "AccessBridgePackages.h"
#ifdef __cplusplus
extern "C" {
#endif
#define null NULL
typedef JOBJECT64 AccessibleContext;
typedef JOBJECT64 AccessibleText;
typedef JOBJECT64 AccessibleValue;
typedef JOBJECT64 AccessibleSelection;
typedef JOBJECT64 Java_Object;
typedef JOBJECT64 PropertyChangeEvent;
typedef JOBJECT64 FocusEvent;
typedef JOBJECT64 CaretEvent;
typedef JOBJECT64 MouseEvent;
typedef JOBJECT64 MenuEvent;
typedef JOBJECT64 AccessibleTable;
typedef JOBJECT64 AccessibleHyperlink;
typedef JOBJECT64 AccessibleHypertext;
typedef void (*Windows_runFP) ();
typedef void (*SetPropertyChangeFP) (AccessBridge_PropertyChangeFP fp);
typedef void (*SetJavaShutdownFP) (AccessBridge_JavaShutdownFP fp);
typedef void (*SetFocusGainedFP) (AccessBridge_FocusGainedFP fp);
typedef void (*SetFocusLostFP) (AccessBridge_FocusLostFP fp);
typedef void (*SetCaretUpdateFP) (AccessBridge_CaretUpdateFP fp);
typedef void (*SetMouseClickedFP) (AccessBridge_MouseClickedFP fp);
typedef void (*SetMouseEnteredFP) (AccessBridge_MouseEnteredFP fp);
typedef void (*SetMouseExitedFP) (AccessBridge_MouseExitedFP fp);
typedef void (*SetMousePressedFP) (AccessBridge_MousePressedFP fp);
typedef void (*SetMouseReleasedFP) (AccessBridge_MouseReleasedFP fp);
typedef void (*SetMenuCanceledFP) (AccessBridge_MenuCanceledFP fp);
typedef void (*SetMenuDeselectedFP) (AccessBridge_MenuDeselectedFP fp);
typedef void (*SetMenuSelectedFP) (AccessBridge_MenuSelectedFP fp);
typedef void (*SetPopupMenuCanceledFP) (AccessBridge_PopupMenuCanceledFP fp);
typedef void (*SetPopupMenuWillBecomeInvisibleFP) (AccessBridge_PopupMenuWillBecomeInvisibleFP fp);
typedef void (*SetPopupMenuWillBecomeVisibleFP) (AccessBridge_PopupMenuWillBecomeVisibleFP fp);
typedef void (*SetPropertyNameChangeFP) (AccessBridge_PropertyNameChangeFP fp);
typedef void (*SetPropertyDescriptionChangeFP) (AccessBridge_PropertyDescriptionChangeFP fp);
typedef void (*SetPropertyStateChangeFP) (AccessBridge_PropertyStateChangeFP fp);
typedef void (*SetPropertyValueChangeFP) (AccessBridge_PropertyValueChangeFP fp);
typedef void (*SetPropertySelectionChangeFP) (AccessBridge_PropertySelectionChangeFP fp);
typedef void (*SetPropertyTextChangeFP) (AccessBridge_PropertyTextChangeFP fp);
typedef void (*SetPropertyCaretChangeFP) (AccessBridge_PropertyCaretChangeFP fp);
typedef void (*SetPropertyVisibleDataChangeFP) (AccessBridge_PropertyVisibleDataChangeFP fp);
typedef void (*SetPropertyChildChangeFP) (AccessBridge_PropertyChildChangeFP fp);
typedef void (*SetPropertyActiveDescendentChangeFP) (AccessBridge_PropertyActiveDescendentChangeFP fp);
typedef void (*SetPropertyTableModelChangeFP) (AccessBridge_PropertyTableModelChangeFP fp);
typedef void (*ReleaseJavaObjectFP) (long vmID, Java_Object object);
typedef BOOL (*GetVersionInfoFP) (long vmID, AccessBridgeVersionInfo *info);
typedef BOOL (*IsJavaWindowFP) (HWND window);
typedef BOOL (*IsSameObjectFP) (long vmID, JOBJECT64 obj1, JOBJECT64 obj2);
typedef BOOL (*GetAccessibleContextFromHWNDFP) (HWND window, long *vmID, AccessibleContext *ac);
typedef HWND (*getHWNDFromAccessibleContextFP) (long vmID, AccessibleContext ac);
typedef BOOL (*GetAccessibleContextAtFP) (long vmID, AccessibleContext acParent,
jint x, jint y, AccessibleContext *ac);
typedef BOOL (*GetAccessibleContextWithFocusFP) (HWND window, long *vmID, AccessibleContext *ac);
typedef BOOL (*GetAccessibleContextInfoFP) (long vmID, AccessibleContext ac, AccessibleContextInfo *info);
typedef AccessibleContext (*GetAccessibleChildFromContextFP) (long vmID, AccessibleContext ac, jint i);
typedef AccessibleContext (*GetAccessibleParentFromContextFP) (long vmID, AccessibleContext ac);
/* begin AccessibleTable */
typedef BOOL (*getAccessibleTableInfoFP) (long vmID, AccessibleContext ac, AccessibleTableInfo *tableInfo);
typedef BOOL (*getAccessibleTableCellInfoFP) (long vmID, AccessibleTable accessibleTable,
jint row, jint column, AccessibleTableCellInfo *tableCellInfo);
typedef BOOL (*getAccessibleTableRowHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
typedef BOOL (*getAccessibleTableColumnHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
typedef AccessibleContext (*getAccessibleTableRowDescriptionFP) (long vmID, AccessibleContext acParent, jint row);
typedef AccessibleContext (*getAccessibleTableColumnDescriptionFP) (long vmID, AccessibleContext acParent, jint column);
typedef jint (*getAccessibleTableRowSelectionCountFP) (long vmID, AccessibleTable table);
typedef BOOL (*isAccessibleTableRowSelectedFP) (long vmID, AccessibleTable table, jint row);
typedef BOOL (*getAccessibleTableRowSelectionsFP) (long vmID, AccessibleTable table, jint count,
jint *selections);
typedef jint (*getAccessibleTableColumnSelectionCountFP) (long vmID, AccessibleTable table);
typedef BOOL (*isAccessibleTableColumnSelectedFP) (long vmID, AccessibleTable table, jint column);
typedef BOOL (*getAccessibleTableColumnSelectionsFP) (long vmID, AccessibleTable table, jint count,
jint *selections);
typedef jint (*getAccessibleTableRowFP) (long vmID, AccessibleTable table, jint index);
typedef jint (*getAccessibleTableColumnFP) (long vmID, AccessibleTable table, jint index);
typedef jint (*getAccessibleTableIndexFP) (long vmID, AccessibleTable table, jint row, jint column);
/* end AccessibleTable */
/* AccessibleRelationSet */
typedef BOOL (*getAccessibleRelationSetFP) (long vmID, AccessibleContext accessibleContext,
AccessibleRelationSetInfo *relationSetInfo);
/* AccessibleHypertext */
typedef BOOL (*getAccessibleHypertextFP)(long vmID, AccessibleContext accessibleContext,
AccessibleHypertextInfo *hypertextInfo);
typedef BOOL (*activateAccessibleHyperlinkFP)(long vmID, AccessibleContext accessibleContext,
AccessibleHyperlink accessibleHyperlink);
typedef jint (*getAccessibleHyperlinkCountFP)(const long vmID,
const AccessibleContext accessibleContext);
typedef BOOL (*getAccessibleHypertextExtFP) (const long vmID,
const AccessibleContext accessibleContext,
const jint nStartIndex,
AccessibleHypertextInfo *hypertextInfo);
typedef jint (*getAccessibleHypertextLinkIndexFP)(const long vmID,
const AccessibleHypertext hypertext,
const jint nIndex);
typedef BOOL (*getAccessibleHyperlinkFP)(const long vmID,
const AccessibleHypertext hypertext,
const jint nIndex,
AccessibleHyperlinkInfo *hyperlinkInfo);
/* Accessible KeyBindings, Icons and Actions */
typedef BOOL (*getAccessibleKeyBindingsFP)(long vmID, AccessibleContext accessibleContext,
AccessibleKeyBindings *keyBindings);
typedef BOOL (*getAccessibleIconsFP)(long vmID, AccessibleContext accessibleContext,
AccessibleIcons *icons);
typedef BOOL (*getAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext,
AccessibleActions *actions);
typedef BOOL (*doAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext,
AccessibleActionsToDo *actionsToDo, jint *failure);
/* AccessibleText */
typedef BOOL (*GetAccessibleTextInfoFP) (long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y);
typedef BOOL (*GetAccessibleTextItemsFP) (long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index);
typedef BOOL (*GetAccessibleTextSelectionInfoFP) (long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection);
typedef BOOL (*GetAccessibleTextAttributesFP) (long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes);
typedef BOOL (*GetAccessibleTextRectFP) (long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index);
typedef BOOL (*GetAccessibleTextLineBoundsFP) (long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex);
typedef BOOL (*GetAccessibleTextRangeFP) (long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len);
typedef BOOL (*GetCurrentAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
typedef BOOL (*GetMaximumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
typedef BOOL (*GetMinimumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len);
typedef void (*AddAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
typedef void (*ClearAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as);
typedef JOBJECT64 (*GetAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
typedef int (*GetAccessibleSelectionCountFromContextFP) (long vmID, AccessibleSelection as);
typedef BOOL (*IsAccessibleChildSelectedFromContextFP) (long vmID, AccessibleSelection as, int i);
typedef void (*RemoveAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i);
typedef void (*SelectAllAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as);
/* Utility methods */
typedef BOOL (*setTextContentsFP) (const long vmID, const AccessibleContext ac, const wchar_t *text);
typedef AccessibleContext (*getParentWithRoleFP) (const long vmID, const AccessibleContext ac, const wchar_t *role);
typedef AccessibleContext (*getParentWithRoleElseRootFP) (const long vmID, const AccessibleContext ac, const wchar_t *role);
typedef AccessibleContext (*getTopLevelObjectFP) (const long vmID, const AccessibleContext ac);
typedef int (*getObjectDepthFP) (const long vmID, const AccessibleContext ac);
typedef AccessibleContext (*getActiveDescendentFP) (const long vmID, const AccessibleContext ac);
typedef BOOL (*getVirtualAccessibleNameFP) (const long vmID, const AccessibleContext accessibleContext,
wchar_t *name, int len);
typedef BOOL (*requestFocusFP) (const long vmID, const AccessibleContext accessibleContext);
typedef BOOL (*selectTextRangeFP) (const long vmID, const AccessibleContext accessibleContext,
const int startIndex, const int endIndex);
typedef BOOL (*getTextAttributesInRangeFP) (const long vmID, const AccessibleContext accessibleContext,
const int startIndex, const int endIndex,
AccessibleTextAttributesInfo *attributes, short *len);
typedef int (*getVisibleChildrenCountFP) (const long vmID, const AccessibleContext accessibleContext);
typedef BOOL (*getVisibleChildrenFP) (const long vmID, const AccessibleContext accessibleContext,
const int startIndex, VisibleChildrenInfo *children);
typedef BOOL (*setCaretPositionFP) (const long vmID, const AccessibleContext accessibleContext, const int position);
typedef BOOL (*getCaretLocationFP) (long vmID, AccessibleContext ac, AccessibleTextRectInfo *rectInfo, jint index);
typedef int (*getEventsWaitingFP) ();
typedef struct AccessBridgeFPsTag {
Windows_runFP Windows_run;
SetPropertyChangeFP SetPropertyChange;
SetJavaShutdownFP SetJavaShutdown;
SetFocusGainedFP SetFocusGained;
SetFocusLostFP SetFocusLost;
SetCaretUpdateFP SetCaretUpdate;
SetMouseClickedFP SetMouseClicked;
SetMouseEnteredFP SetMouseEntered;
SetMouseExitedFP SetMouseExited;
SetMousePressedFP SetMousePressed;
SetMouseReleasedFP SetMouseReleased;
SetMenuCanceledFP SetMenuCanceled;
SetMenuDeselectedFP SetMenuDeselected;
SetMenuSelectedFP SetMenuSelected;
SetPopupMenuCanceledFP SetPopupMenuCanceled;
SetPopupMenuWillBecomeInvisibleFP SetPopupMenuWillBecomeInvisible;
SetPopupMenuWillBecomeVisibleFP SetPopupMenuWillBecomeVisible;
SetPropertyNameChangeFP SetPropertyNameChange;
SetPropertyDescriptionChangeFP SetPropertyDescriptionChange;
SetPropertyStateChangeFP SetPropertyStateChange;
SetPropertyValueChangeFP SetPropertyValueChange;
SetPropertySelectionChangeFP SetPropertySelectionChange;
SetPropertyTextChangeFP SetPropertyTextChange;
SetPropertyCaretChangeFP SetPropertyCaretChange;
SetPropertyVisibleDataChangeFP SetPropertyVisibleDataChange;
SetPropertyChildChangeFP SetPropertyChildChange;
SetPropertyActiveDescendentChangeFP SetPropertyActiveDescendentChange;
SetPropertyTableModelChangeFP SetPropertyTableModelChange;
ReleaseJavaObjectFP ReleaseJavaObject;
GetVersionInfoFP GetVersionInfo;
IsJavaWindowFP IsJavaWindow;
IsSameObjectFP IsSameObject;
GetAccessibleContextFromHWNDFP GetAccessibleContextFromHWND;
getHWNDFromAccessibleContextFP getHWNDFromAccessibleContext;
GetAccessibleContextAtFP GetAccessibleContextAt;
GetAccessibleContextWithFocusFP GetAccessibleContextWithFocus;
GetAccessibleContextInfoFP GetAccessibleContextInfo;
GetAccessibleChildFromContextFP GetAccessibleChildFromContext;
GetAccessibleParentFromContextFP GetAccessibleParentFromContext;
getAccessibleTableInfoFP getAccessibleTableInfo;
getAccessibleTableCellInfoFP getAccessibleTableCellInfo;
getAccessibleTableRowHeaderFP getAccessibleTableRowHeader;
getAccessibleTableColumnHeaderFP getAccessibleTableColumnHeader;
getAccessibleTableRowDescriptionFP getAccessibleTableRowDescription;
getAccessibleTableColumnDescriptionFP getAccessibleTableColumnDescription;
getAccessibleTableRowSelectionCountFP getAccessibleTableRowSelectionCount;
isAccessibleTableRowSelectedFP isAccessibleTableRowSelected;
getAccessibleTableRowSelectionsFP getAccessibleTableRowSelections;
getAccessibleTableColumnSelectionCountFP getAccessibleTableColumnSelectionCount;
isAccessibleTableColumnSelectedFP isAccessibleTableColumnSelected;
getAccessibleTableColumnSelectionsFP getAccessibleTableColumnSelections;
getAccessibleTableRowFP getAccessibleTableRow;
getAccessibleTableColumnFP getAccessibleTableColumn;
getAccessibleTableIndexFP getAccessibleTableIndex;
getAccessibleRelationSetFP getAccessibleRelationSet;
getAccessibleHypertextFP getAccessibleHypertext;
activateAccessibleHyperlinkFP activateAccessibleHyperlink;
getAccessibleHyperlinkCountFP getAccessibleHyperlinkCount;
getAccessibleHypertextExtFP getAccessibleHypertextExt;
getAccessibleHypertextLinkIndexFP getAccessibleHypertextLinkIndex;
getAccessibleHyperlinkFP getAccessibleHyperlink;
getAccessibleKeyBindingsFP getAccessibleKeyBindings;
getAccessibleIconsFP getAccessibleIcons;
getAccessibleActionsFP getAccessibleActions;
doAccessibleActionsFP doAccessibleActions;
GetAccessibleTextInfoFP GetAccessibleTextInfo;
GetAccessibleTextItemsFP GetAccessibleTextItems;
GetAccessibleTextSelectionInfoFP GetAccessibleTextSelectionInfo;
GetAccessibleTextAttributesFP GetAccessibleTextAttributes;
GetAccessibleTextRectFP GetAccessibleTextRect;
GetAccessibleTextLineBoundsFP GetAccessibleTextLineBounds;
GetAccessibleTextRangeFP GetAccessibleTextRange;
GetCurrentAccessibleValueFromContextFP GetCurrentAccessibleValueFromContext;
GetMaximumAccessibleValueFromContextFP GetMaximumAccessibleValueFromContext;
GetMinimumAccessibleValueFromContextFP GetMinimumAccessibleValueFromContext;
AddAccessibleSelectionFromContextFP AddAccessibleSelectionFromContext;
ClearAccessibleSelectionFromContextFP ClearAccessibleSelectionFromContext;
GetAccessibleSelectionFromContextFP GetAccessibleSelectionFromContext;
GetAccessibleSelectionCountFromContextFP GetAccessibleSelectionCountFromContext;
IsAccessibleChildSelectedFromContextFP IsAccessibleChildSelectedFromContext;
RemoveAccessibleSelectionFromContextFP RemoveAccessibleSelectionFromContext;
SelectAllAccessibleSelectionFromContextFP SelectAllAccessibleSelectionFromContext;
setTextContentsFP setTextContents;
getParentWithRoleFP getParentWithRole;
getTopLevelObjectFP getTopLevelObject;
getParentWithRoleElseRootFP getParentWithRoleElseRoot;
getObjectDepthFP getObjectDepth;
getActiveDescendentFP getActiveDescendent;
getVirtualAccessibleNameFP getVirtualAccessibleName;
requestFocusFP requestFocus;
selectTextRangeFP selectTextRange;
getTextAttributesInRangeFP getTextAttributesInRange;
getVisibleChildrenCountFP getVisibleChildrenCount;
getVisibleChildrenFP getVisibleChildren;
setCaretPositionFP setCaretPosition;
getCaretLocationFP getCaretLocation;
getEventsWaitingFP getEventsWaiting;
} AccessBridgeFPs;
/**
* Initialize the world
*/
BOOL initializeAccessBridge();
BOOL shutdownAccessBridge();
/**
* Window routines
*/
BOOL IsJavaWindow(HWND window);
// Returns the virtual machine ID and AccessibleContext for a top-level window
BOOL GetAccessibleContextFromHWND(HWND target, long *vmID, AccessibleContext *ac);
// Returns the HWND from the AccessibleContext of a top-level window
HWND getHWNDFromAccessibleContext(long vmID, AccessibleContext ac);
/**
* Event handling routines
*/
void SetJavaShutdown(AccessBridge_JavaShutdownFP fp);
void SetFocusGained(AccessBridge_FocusGainedFP fp);
void SetFocusLost(AccessBridge_FocusLostFP fp);
void SetCaretUpdate(AccessBridge_CaretUpdateFP fp);
void SetMouseClicked(AccessBridge_MouseClickedFP fp);
void SetMouseEntered(AccessBridge_MouseEnteredFP fp);
void SetMouseExited(AccessBridge_MouseExitedFP fp);
void SetMousePressed(AccessBridge_MousePressedFP fp);
void SetMouseReleased(AccessBridge_MouseReleasedFP fp);
void SetMenuCanceled(AccessBridge_MenuCanceledFP fp);
void SetMenuDeselected(AccessBridge_MenuDeselectedFP fp);
void SetMenuSelected(AccessBridge_MenuSelectedFP fp);
void SetPopupMenuCanceled(AccessBridge_PopupMenuCanceledFP fp);
void SetPopupMenuWillBecomeInvisible(AccessBridge_PopupMenuWillBecomeInvisibleFP fp);
void SetPopupMenuWillBecomeVisible(AccessBridge_PopupMenuWillBecomeVisibleFP fp);
void SetPropertyNameChange(AccessBridge_PropertyNameChangeFP fp);
void SetPropertyDescriptionChange(AccessBridge_PropertyDescriptionChangeFP fp);
void SetPropertyStateChange(AccessBridge_PropertyStateChangeFP fp);
void SetPropertyValueChange(AccessBridge_PropertyValueChangeFP fp);
void SetPropertySelectionChange(AccessBridge_PropertySelectionChangeFP fp);
void SetPropertyTextChange(AccessBridge_PropertyTextChangeFP fp);
void SetPropertyCaretChange(AccessBridge_PropertyCaretChangeFP fp);
void SetPropertyVisibleDataChange(AccessBridge_PropertyVisibleDataChangeFP fp);
void SetPropertyChildChange(AccessBridge_PropertyChildChangeFP fp);
void SetPropertyActiveDescendentChange(AccessBridge_PropertyActiveDescendentChangeFP fp);
void SetPropertyTableModelChange(AccessBridge_PropertyTableModelChangeFP fp);
/**
* General routines
*/
void ReleaseJavaObject(long vmID, Java_Object object);
BOOL GetVersionInfo(long vmID, AccessBridgeVersionInfo *info);
HWND GetHWNDFromAccessibleContext(long vmID, JOBJECT64 accesibleContext);
/**
* Accessible Context routines
*/
BOOL GetAccessibleContextAt(long vmID, AccessibleContext acParent,
jint x, jint y, AccessibleContext *ac);
BOOL GetAccessibleContextWithFocus(HWND window, long *vmID, AccessibleContext *ac);
BOOL GetAccessibleContextInfo(long vmID, AccessibleContext ac, AccessibleContextInfo *info);
AccessibleContext GetAccessibleChildFromContext(long vmID, AccessibleContext ac, jint index);
AccessibleContext GetAccessibleParentFromContext(long vmID, AccessibleContext ac);
/**
* Accessible Text routines
*/
BOOL GetAccessibleTextInfo(long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y);
BOOL GetAccessibleTextItems(long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index);
BOOL GetAccessibleTextSelectionInfo(long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection);
BOOL GetAccessibleTextAttributes(long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes);
BOOL GetAccessibleTextRect(long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index);
BOOL GetAccessibleTextLineBounds(long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex);
BOOL GetAccessibleTextRange(long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len);
/* begin AccessibleTable routines */
BOOL getAccessibleTableInfo(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
BOOL getAccessibleTableCellInfo(long vmID, AccessibleTable accessibleTable, jint row, jint column,
AccessibleTableCellInfo *tableCellInfo);
BOOL getAccessibleTableRowHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
BOOL getAccessibleTableColumnHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo);
AccessibleContext getAccessibleTableRowDescription(long vmID, AccessibleContext acParent, jint row);
AccessibleContext getAccessibleTableColumnDescription(long vmID, AccessibleContext acParent, jint column);
jint getAccessibleTableRowSelectionCount(long vmID, AccessibleTable table);
BOOL isAccessibleTableRowSelected(long vmID, AccessibleTable table, jint row);
BOOL getAccessibleTableRowSelections(long vmID, AccessibleTable table, jint count, jint *selections);
jint getAccessibleTableColumnSelectionCount(long vmID, AccessibleTable table);
BOOL isAccessibleTableColumnSelected(long vmID, AccessibleTable table, jint column);
BOOL getAccessibleTableColumnSelections(long vmID, AccessibleTable table, jint count, jint *selections);
jint getAccessibleTableRow(long vmID, AccessibleTable table, jint index);
jint getAccessibleTableColumn(long vmID, AccessibleTable table, jint index);
jint getAccessibleTableIndex(long vmID, AccessibleTable table, jint row, jint column);
/* end AccessibleTable */
/* ----- AccessibleRelationSet routines */
BOOL getAccessibleRelationSet(long vmID, AccessibleContext accessibleContext,
AccessibleRelationSetInfo *relationSetInfo);
/* ----- AccessibleHypertext routines */
/*
* Returns hypertext information associated with a component.
*/
BOOL getAccessibleHypertext(long vmID, AccessibleContext accessibleContext,
AccessibleHypertextInfo *hypertextInfo);
/*
* Requests that a hyperlink be activated.
*/
BOOL activateAccessibleHyperlink(long vmID, AccessibleContext accessibleContext,
AccessibleHyperlink accessibleHyperlink);
/*
* Returns the number of hyperlinks in a component
* Maps to AccessibleHypertext.getLinkCount.
* Returns -1 on error.
*/
jint getAccessibleHyperlinkCount(const long vmID,
const AccessibleHypertext hypertext);
/*
* This method is used to iterate through the hyperlinks in a component. It
* returns hypertext information for a component starting at hyperlink index
* nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will
* be returned for each call to this method.
* Returns FALSE on error.
*/
BOOL getAccessibleHypertextExt(const long vmID,
const AccessibleContext accessibleContext,
const jint nStartIndex,
/* OUT */ AccessibleHypertextInfo *hypertextInfo);
/*
* Returns the index into an array of hyperlinks that is associated with
* a character index in document; maps to AccessibleHypertext.getLinkIndex
* Returns -1 on error.
*/
jint getAccessibleHypertextLinkIndex(const long vmID,
const AccessibleHypertext hypertext,
const jint nIndex);
/*
* Returns the nth hyperlink in a document
* Maps to AccessibleHypertext.getLink.
* Returns FALSE on error
*/
BOOL getAccessibleHyperlink(const long vmID,
const AccessibleHypertext hypertext,
const jint nIndex,
/* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo);
/* Accessible KeyBindings, Icons and Actions */
/*
* Returns a list of key bindings associated with a component.
*/
BOOL getAccessibleKeyBindings(long vmID, AccessibleContext accessibleContext,
AccessibleKeyBindings *keyBindings);
/*
* Returns a list of icons associate with a component.
*/
BOOL getAccessibleIcons(long vmID, AccessibleContext accessibleContext,
AccessibleIcons *icons);
/*
* Returns a list of actions that a component can perform.
*/
BOOL getAccessibleActions(long vmID, AccessibleContext accessibleContext,
AccessibleActions *actions);
/*
* Request that a list of AccessibleActions be performed by a component.
* Returns TRUE if all actions are performed. Returns FALSE
* when the first requested action fails in which case "failure"
* contains the index of the action that failed.
*/
BOOL doAccessibleActions(long vmID, AccessibleContext accessibleContext,
AccessibleActionsToDo *actionsToDo, jint *failure);
/* Additional utility methods */
/*
* Returns whether two object references refer to the same object.
*/
BOOL IsSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2);
/**
* Sets editable text contents. The AccessibleContext must implement AccessibleEditableText and
* be editable. The maximum text length that can be set is MAX_STRING_SIZE - 1.
* Returns whether successful
*/
BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text);
/**
* Returns the Accessible Context with the specified role that is the
* ancestor of a given object. The role is one of the role strings
* defined in AccessBridgePackages.h
* If there is no ancestor object that has the specified role,
* returns (AccessibleContext)0.
*/
AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext,
const wchar_t *role);
/**
* Returns the Accessible Context with the specified role that is the
* ancestor of a given object. The role is one of the role strings
* defined in AccessBridgePackages.h. If an object with the specified
* role does not exist, returns the top level object for the Java Window.
* Returns (AccessibleContext)0 on error.
*/
AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext,
const wchar_t *role);
/**
* Returns the Accessible Context for the top level object in
* a Java Window. This is same Accessible Context that is obtained
* from GetAccessibleContextFromHWND for that window. Returns
* (AccessibleContext)0 on error.
*/
AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext);
/**
* Returns how deep in the object hierarchy a given object is.
* The top most object in the object hierarchy has an object depth of 0.
* Returns -1 on error.
*/
int getObjectDepth (const long vmID, const AccessibleContext accessibleContext);
/**
* Returns the Accessible Context of the current ActiveDescendent of an object.
* This method assumes the ActiveDescendent is the component that is currently
* selected in a container object.
* Returns (AccessibleContext)0 on error or if there is no selection.
*/
AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext);
/**
/**
* Accessible Value routines
*/
BOOL GetCurrentAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
BOOL GetMaximumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
BOOL GetMinimumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len);
/**
* Accessible Selection routines
*/
void AddAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
void ClearAccessibleSelectionFromContext(long vmID, AccessibleSelection as);
JOBJECT64 GetAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
int GetAccessibleSelectionCountFromContext(long vmID, AccessibleSelection as);
BOOL IsAccessibleChildSelectedFromContext(long vmID, AccessibleSelection as, int i);
void RemoveAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i);
void SelectAllAccessibleSelectionFromContext(long vmID, AccessibleSelection as);
/**
* Additional methods for Teton
*/
/**
* Gets the AccessibleName for a component based upon the JAWS algorithm. Returns
* whether successful.
*
* Bug ID 4916682 - Implement JAWS AccessibleName policy
*/
BOOL getVirtualAccessibleName(const long vmID, const AccessibleContext accessibleContext,
wchar_t *name, int len);
/**
* Request focus for a component. Returns whether successful.
*
* Bug ID 4944757 - requestFocus method needed
*/
BOOL requestFocus(const long vmID, const AccessibleContext accessibleContext);
/**
* Selects text between two indices. Selection includes the text at the start index
* and the text at the end index. Returns whether successful.
*
* Bug ID 4944758 - selectTextRange method needed
*/
BOOL selectTextRange(const long vmID, const AccessibleContext accessibleContext, const int startIndex,
const int endIndex);
/**
* Get text attributes between two indices. The attribute list includes the text at the
* start index and the text at the end index. Returns whether successful;
*
* Bug ID 4944761 - getTextAttributes between two indices method needed
*/
BOOL getTextAttributesInRange(const long vmID, const AccessibleContext accessibleContext,
const int startIndex, const int endIndex,
AccessibleTextAttributesInfo *attributes, short *len);
/**
* Returns the number of visible children of a component. Returns -1 on error.
*
* Bug ID 4944762- getVisibleChildren for list-like components needed
*/
int getVisibleChildrenCount(const long vmID, const AccessibleContext accessibleContext);
/**
* Gets the visible children of an AccessibleContext. Returns whether successful.
*
* Bug ID 4944762- getVisibleChildren for list-like components needed
*/
BOOL getVisibleChildren(const long vmID, const AccessibleContext accessibleContext,
const int startIndex,
VisibleChildrenInfo *visibleChildrenInfo);
/**
* Set the caret to a text position. Returns whether successful.
*
* Bug ID 4944770 - setCaretPosition method needed
*/
BOOL setCaretPosition(const long vmID, const AccessibleContext accessibleContext,
const int position);
/**
* Gets the text caret location
*/
BOOL getCaretLocation(long vmID, AccessibleContext ac,
AccessibleTextRectInfo *rectInfo, jint index);
/**
* Gets the number of events waiting to fire
*/
int getEventsWaiting();
#ifdef __cplusplus
}
#endif

@ -0,0 +1,59 @@
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#ifndef _JAVASOFT_JAWT_MD_H_
#define _JAVASOFT_JAWT_MD_H_
#include <windows.h>
#include "jawt.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Win32-specific declarations for AWT native interface.
* See notes in jawt.h for an example of use.
*/
typedef struct jawt_Win32DrawingSurfaceInfo {
/* Native window, DDB, or DIB handle */
union {
HWND hwnd;
HBITMAP hbitmap;
void* pbits;
};
/*
* This HDC should always be used instead of the HDC returned from
* BeginPaint() or any calls to GetDC().
*/
HDC hdc;
HPALETTE hpalette;
} JAWT_Win32DrawingSurfaceInfo;
#ifdef __cplusplus
}
#endif
#endif /* !_JAVASOFT_JAWT_MD_H_ */

@ -0,0 +1,37 @@
/*
* Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#define JNIEXPORT __declspec(dllexport)
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stdcall
typedef long jint;
typedef __int64 jlong;
typedef signed char jbyte;
#endif /* !_JAVASOFT_JNI_MD_H_ */

@ -0,0 +1,207 @@
#include <iostream>
#include <jni.h>
#include <jni_md.h>
#include <jvmti.h>
#include "arthas_VmTool.h" // under target/native/javah/
static jvmtiEnv *jvmti;
static jlong tagCounter = 0;
struct LimitCounter {
jint currentCounter;
jint limitValue;
void init(jint limit) {
currentCounter = 0;
limitValue = limit;
}
void countDown() {
currentCounter++;
}
bool allow() {
if (limitValue < 0) {
return true;
}
return limitValue > currentCounter;
}
};
// 每次 IterateOverInstancesOfClass 调用前需要先 init
static LimitCounter limitCounter = {0, 0};
extern "C"
int init_agent(JavaVM *vm, void *reserved) {
jint rc;
/* Get JVMTI environment */
rc = vm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_2);
if (rc != JNI_OK) {
fprintf(stderr, "ERROR: arthas vmtool Unable to create jvmtiEnv, GetEnv failed, error=%d\n", rc);
return -1;
}
jvmtiCapabilities capabilities = {0};
capabilities.can_tag_objects = 1;
jvmtiError error = jvmti->AddCapabilities(&capabilities);
if (error) {
fprintf(stderr, "ERROR: arthas vmtool JVMTI AddCapabilities failed!%u\n", error);
return JNI_FALSE;
}
return JNI_OK;
}
extern "C" JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
return init_agent(vm, reserved);
}
extern "C" JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
return init_agent(vm, reserved);
}
extern "C" JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM* vm, void* reserved) {
init_agent(vm, reserved);
return JNI_VERSION_1_6;
}
extern "C"
JNIEXPORT void JNICALL
Java_arthas_VmTool_forceGc0(JNIEnv *env, jclass thisClass) {
jvmti->ForceGarbageCollection();
}
extern "C"
jlong getTag() {
return ++tagCounter;
}
extern "C"
jvmtiIterationControl JNICALL
HeapObjectCallback(jlong class_tag, jlong size, jlong *tag_ptr, void *user_data) {
jlong *data = static_cast<jlong *>(user_data);
*tag_ptr = *data;
limitCounter.countDown();
if (limitCounter.allow()) {
return JVMTI_ITERATION_CONTINUE;
}else {
return JVMTI_ITERATION_ABORT;
}
}
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_arthas_VmTool_getInstances0(JNIEnv *env, jclass thisClass, jclass klass, jint limit) {
jlong tag = getTag();
limitCounter.init(limit);
jvmtiError error = jvmti->IterateOverInstancesOfClass(klass, JVMTI_HEAP_OBJECT_EITHER,
HeapObjectCallback, &tag);
if (error) {
printf("ERROR: JVMTI IterateOverInstancesOfClass failed!%u\n", error);
return NULL;
}
jint count = 0;
jobject *instances;
error = jvmti->GetObjectsWithTags(1, &tag, &count, &instances, NULL);
if (error) {
printf("ERROR: JVMTI GetObjectsWithTags failed!%u\n", error);
return NULL;
}
jobjectArray array = env->NewObjectArray(count, klass, NULL);
//添加元素到数组
for (int i = 0; i < count; i++) {
env->SetObjectArrayElement(array, i, instances[i]);
}
jvmti->Deallocate(reinterpret_cast<unsigned char *>(instances));
return array;
}
extern "C"
JNIEXPORT jlong JNICALL
Java_arthas_VmTool_sumInstanceSize0(JNIEnv *env, jclass thisClass, jclass klass) {
jlong tag = getTag();
limitCounter.init(-1);
jvmtiError error = jvmti->IterateOverInstancesOfClass(klass, JVMTI_HEAP_OBJECT_EITHER,
HeapObjectCallback, &tag);
if (error) {
printf("ERROR: JVMTI IterateOverInstancesOfClass failed!%u\n", error);
return -1;
}
jint count = 0;
jobject *instances;
error = jvmti->GetObjectsWithTags(1, &tag, &count, &instances, NULL);
if (error) {
printf("ERROR: JVMTI GetObjectsWithTags failed!%u\n", error);
return -1;
}
jlong sum = 0;
for (int i = 0; i < count; i++) {
jlong size = 0;
jvmti->GetObjectSize(instances[i], &size);
sum = sum + size;
}
jvmti->Deallocate(reinterpret_cast<unsigned char *>(instances));
return sum;
}
extern "C"
JNIEXPORT jlong JNICALL Java_arthas_VmTool_getInstanceSize0
(JNIEnv *env, jclass thisClass, jobject instance) {
jlong size = -1;
jvmtiError error = jvmti->GetObjectSize(instance, &size);
if (error) {
printf("ERROR: JVMTI GetObjectSize failed!%u\n", error);
}
return size;
}
extern "C"
JNIEXPORT jlong JNICALL
Java_arthas_VmTool_countInstances0(JNIEnv *env, jclass thisClass, jclass klass) {
jlong tag = getTag();
limitCounter.init(-1);
jvmtiError error = jvmti->IterateOverInstancesOfClass(klass, JVMTI_HEAP_OBJECT_EITHER,
HeapObjectCallback, &tag);
if (error) {
printf("ERROR: JVMTI IterateOverInstancesOfClass failed!%u\n", error);
return -1;
}
jint count = 0;
error = jvmti->GetObjectsWithTags(1, &tag, &count, NULL, NULL);
if (error) {
printf("ERROR: JVMTI GetObjectsWithTags failed!%u\n", error);
return -1;
}
return count;
}
extern "C"
JNIEXPORT jobjectArray JNICALL Java_arthas_VmTool_getAllLoadedClasses0
(JNIEnv *env, jclass thisClass, jclass kclass) {
jclass *classes;
jint count = 0;
jvmtiError error = jvmti->GetLoadedClasses(&count, &classes);
if (error) {
printf("ERROR: JVMTI GetLoadedClasses failed!\n");
return NULL;
}
jobjectArray array = env->NewObjectArray(count, kclass, NULL);
//添加元素到数组
for (int i = 0; i < count; i++) {
env->SetObjectArrayElement(array, i, classes[i]);
}
jvmti->Deallocate(reinterpret_cast<unsigned char *>(classes));
return array;
}

@ -0,0 +1,185 @@
package arthas;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicLong;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import com.taobao.arthas.common.VmToolUtils;
/**
* jvm-Xms128m -Xmx128m
*/
public class VmToolTest {
private VmTool initVmTool() {
File path = new File(VmTool.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getParentFile();
String libPath = new File(path, VmToolUtils.detectLibName()).getAbsolutePath();
return VmTool.getInstance(libPath);
}
/**
* macbook
* allLoadedClasses->1050
* arthas.VmTool@5bb21b69 arthas.VmTool@6b9651f3
* before instances->[arthas.VmTool@5bb21b69, arthas.VmTool@6b9651f3]
* size->16
* count->2
* sum size->32
* null null
* after instances->[]
*/
@Test
public void testIsSnapshot() {
try {
VmTool vmtool = initVmTool();
//调用native方法获取已加载的类不包括小类型(如int)
Class<?>[] allLoadedClasses = vmtool.getAllLoadedClasses();
System.out.println("allLoadedClasses->" + allLoadedClasses.length);
//通过下面的例子可以看到getInstances(Class<T> klass)拿到的是当前存活的所有对象
WeakReference<VmToolTest> weakReference1 = new WeakReference<VmToolTest>(new VmToolTest());
WeakReference<VmToolTest> weakReference2 = new WeakReference<VmToolTest>(new VmToolTest());
System.out.println(weakReference1.get() + " " + weakReference2.get());
VmTool[] beforeInstances = vmtool.getInstances(VmTool.class);
System.out.println("before instances->" + beforeInstances);
System.out.println("size->" + vmtool.getInstanceSize(weakReference1.get()));
System.out.println("count->" + vmtool.countInstances(VmTool.class));
System.out.println("sum size->" + vmtool.sumInstanceSize(VmTool.class));
beforeInstances = null;
vmtool.forceGc();
Thread.sleep(100);
System.out.println(weakReference1.get() + " " + weakReference2.get());
VmTool[] afterInstances = vmtool.getInstances(VmTool.class);
System.out.println("after instances->" + afterInstances);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testGetInstancesMemoryLeak() {
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool vmtool = initVmTool();
final AtomicLong totalTime = new AtomicLong();
//本地测试请改成200000
for (int i = 1; i <= 2; i++) {
long start = System.currentTimeMillis();
WeakReference<Object[]> reference = new WeakReference<Object[]>(vmtool.getInstances(Object.class));
Object[] instances = reference.get();
long cost = System.currentTimeMillis() - start;
totalTime.addAndGet(cost);
System.out.println(i + " instance size:" + (instances == null ? 0 : instances.length) + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
instances = null;
vmtool.forceGc();
}
}
@Test
public void testSumInstancesMemoryLeak() {
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool vmtool = initVmTool();
final AtomicLong totalTime = new AtomicLong();
//本地测试请改成200000
for (int i = 1; i <= 2; i++) {
long start = System.currentTimeMillis();
long sum = vmtool.sumInstanceSize(Object.class);
long cost = System.currentTimeMillis() - start;
totalTime.addAndGet(cost);
System.out.println(i + " sum:" + sum + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
}
}
@Test
public void testCountInstancesMemoryLeak() {
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool vmtool = initVmTool();
final AtomicLong totalTime = new AtomicLong();
//本地测试请改成200000
for (int i = 1; i <= 2; i++) {
long start = System.currentTimeMillis();
long count = vmtool.countInstances(Object.class);
long cost = System.currentTimeMillis() - start;
totalTime.addAndGet(cost);
System.out.println(i + " count:" + count + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
}
}
@Test
public void testGetAllLoadedClassesMemoryLeak() {
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool vmtool = initVmTool();
final AtomicLong totalTime = new AtomicLong();
//本地测试请改成200000
for (int i = 1; i <= 2; i++) {
long start = System.currentTimeMillis();
Class<?>[] allLoadedClasses = vmtool.getAllLoadedClasses();
long cost = System.currentTimeMillis() - start;
totalTime.addAndGet(cost);
System.out.println(i + " class size:" + allLoadedClasses.length + ", cost " + cost + "ms avgCost " + totalTime.doubleValue() / i + "ms");
allLoadedClasses = null;
}
}
class LimitTest {
}
@Test
public void test_getInstances_lmiit() {
VmTool vmtool = initVmTool();
ArrayList<LimitTest> list = new ArrayList<LimitTest>();
for (int i = 0; i < 10; ++i) {
list.add(new LimitTest());
}
LimitTest[] instances = vmtool.getInstances(LimitTest.class, 5);
Assertions.assertThat(instances).hasSize(5);
LimitTest[] instances2 = vmtool.getInstances(LimitTest.class, -1);
Assertions.assertThat(instances2).hasSize(10);
LimitTest[] instances3 = vmtool.getInstances(LimitTest.class, 1);
Assertions.assertThat(instances3).hasSize(1);
}
interface III {
}
class AAA implements III {
}
@Test
public void test_getInstances_interface() {
AAA aaa = new AAA();
VmTool vmtool = initVmTool();
III[] interfaceInstances = vmtool.getInstances(III.class);
Assertions.assertThat(interfaceInstances.length).isEqualTo(1);
AAA[] ObjectInstances = vmtool.getInstances(AAA.class);
Assertions.assertThat(ObjectInstances.length).isEqualTo(1);
Assertions.assertThat(interfaceInstances[0]).isEqualTo(ObjectInstances[0]);
}
}

@ -33,7 +33,7 @@ exit_on_err()
} }
# maven package the arthas # maven package the arthas
"$DIR/mvnw" clean package -T 2C -Dmaven.test.skip=true -DskipTests=true -Dmaven.javadoc.skip=true -f $DIR/pom.xml \ "$DIR/mvnw" clean package -Dmaven.test.skip=true -DskipTests=true -Dmaven.javadoc.skip=true -f $DIR/pom.xml \
|| exit_on_err 1 "package arthas failed." || exit_on_err 1 "package arthas failed."
rm -r "$DIR/core/src/main/resources/com/taobao/arthas/core/res/version" rm -r "$DIR/core/src/main/resources/com/taobao/arthas/core/res/version"

@ -24,6 +24,7 @@ if ["%~1"]==[""] (
goto exit_bat goto exit_bat
) )
set JAVA_TOOL_OPTIONS
set AGENT_JAR=%BASEDIR%\arthas-agent.jar set AGENT_JAR=%BASEDIR%\arthas-agent.jar
set CORE_JAR=%BASEDIR%\arthas-core.jar set CORE_JAR=%BASEDIR%\arthas-core.jar

@ -8,10 +8,10 @@
# program : Arthas # program : Arthas
# author : Core Engine @ Taobao.com # author : Core Engine @ Taobao.com
# date : 2020-09-27 # date : 2021-06-10
# current arthas script version # current arthas script version
ARTHAS_SCRIPT_VERSION=3.4.3 ARTHAS_SCRIPT_VERSION=3.5.2
# SYNOPSIS # SYNOPSIS
# rreadlink <fileOrDirPath> # rreadlink <fileOrDirPath>
@ -83,22 +83,27 @@ DIR=$(dirname -- "$(rreadlink "${BASH_SOURCE[0]}")")
ARTHAS_HOME= ARTHAS_HOME=
# define arthas's lib # define arthas's lib
ARTHAS_LIB_DIR=${HOME}/.arthas/lib if [ -z "${ARTHAS_LIB_DIR}" ]; then
ARTHAS_LIB_DIR=${HOME}/.arthas/lib
fi
# target process id to attach # target process id to attach
TARGET_PID= TARGET_PID=
# target process id to attach # target process id to attach, default 127.0.0.1
TARGET_IP="127.0.0.1" TARGET_IP=
DEFAULT_TARGET_IP="127.0.0.1"
# telnet port # telnet port, default 3658
TELNET_PORT="3658" TELNET_PORT=
DEFAULT_TELNET_PORT="3658"
# http port # http port, default 8563
HTTP_PORT="8563" HTTP_PORT=
DEFAULT_HTTP_PORT="8563"
# telnet session timeout seconds, default 1800 # telnet session timeout seconds, default 1800
SESSION_TIMEOUT=1800 SESSION_TIMEOUT=
# use specify version # use specify version
USE_VERSION= USE_VERSION=
@ -139,6 +144,18 @@ AGENT_ID=
# stat report url # stat report url
STAT_URL= STAT_URL=
# app name
APP_NAME=
# username
USERNAME=
# password
PASSWORD=
# disabledCommands
DISABLED_COMMANDS=
############ Command Arguments ############ ############ Command Arguments ############
# if arguments contains -c/--command or -f/--batch-file, BATCH_MODE will be true # if arguments contains -c/--command or -f/--batch-file, BATCH_MODE will be true
@ -147,9 +164,6 @@ BATCH_MODE=false
# define arthas's temp dir # define arthas's temp dir
TMP_DIR=/tmp TMP_DIR=/tmp
# last update arthas version
ARTHAS_VERSION=
# arthas remote url # arthas remote url
# https://arthas.aliyun.com/download/3.1.7?mirror=aliyun # https://arthas.aliyun.com/download/3.1.7?mirror=aliyun
REMOTE_DOWNLOAD_URL="https://arthas.aliyun.com/download/PLACEHOLDER_VERSION?mirror=PLACEHOLDER_REPO" REMOTE_DOWNLOAD_URL="https://arthas.aliyun.com/download/PLACEHOLDER_VERSION?mirror=PLACEHOLDER_REPO"
@ -223,6 +237,7 @@ check_permission()
# reset some options for env # reset some options for env
reset_for_env() reset_for_env()
{ {
unset JAVA_TOOL_OPTIONS
# init ARTHAS' lib # init ARTHAS' lib
mkdir -p "${ARTHAS_LIB_DIR}" \ mkdir -p "${ARTHAS_LIB_DIR}" \
@ -393,6 +408,9 @@ Usage:
$0 [-h] [--target-ip <value>] [--telnet-port <value>] $0 [-h] [--target-ip <value>] [--telnet-port <value>]
[--http-port <value>] [--session-timeout <value>] [--arthas-home <value>] [--http-port <value>] [--session-timeout <value>] [--arthas-home <value>]
[--tunnel-server <value>] [--agent-id <value>] [--stat-url <value>] [--tunnel-server <value>] [--agent-id <value>] [--stat-url <value>]
[--app-name <value>]
[--username <value>] [--password <value>]
[--disabled-commands <value>]
[--use-version <value>] [--repo-mirror <value>] [--versions] [--use-http] [--use-version <value>] [--repo-mirror <value>] [--versions] [--use-http]
[--attach-only] [-c <value>] [-f <value>] [-v] [pid] [--attach-only] [-c <value>] [-f <value>] [-v] [pid]
@ -412,6 +430,10 @@ Options and Arguments:
--debug-attach Debug attach agent --debug-attach Debug attach agent
--tunnel-server Remote tunnel server url --tunnel-server Remote tunnel server url
--agent-id Special agent id --agent-id Special agent id
--app-name Special app name
--username Special username
--password Special password
--disabled-commands Disable special commands
--select select target process by classname or JARfilename --select select target process by classname or JARfilename
-c,--command <value> Command to execute, multiple commands separated -c,--command <value> Command to execute, multiple commands separated
by ; by ;
@ -425,15 +447,17 @@ EXAMPLES:
./as.sh <pid> ./as.sh <pid>
./as.sh --target-ip 0.0.0.0 ./as.sh --target-ip 0.0.0.0
./as.sh --telnet-port 9999 --http-port -1 ./as.sh --telnet-port 9999 --http-port -1
./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' ./as.sh --username admin --password <password>
./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' --app-name demoapp
./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' --agent-id bvDOe8XbTM2pQWjF4cfw ./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' --agent-id bvDOe8XbTM2pQWjF4cfw
./as.sh --stat-url 'http://192.168.10.11:8080/api/stat' ./as.sh --stat-url 'http://192.168.10.11:8080/api/stat'
./as.sh -c 'sysprop; thread' <pid> ./as.sh -c 'sysprop; thread' <pid>
./as.sh -f batch.as <pid> ./as.sh -f batch.as <pid>
./as.sh --use-version 3.4.3 ./as.sh --use-version 3.5.2
./as.sh --session-timeout 3600 ./as.sh --session-timeout 3600
./as.sh --attach-only ./as.sh --attach-only
./as.sh --select arthas-demo ./as.sh --disabled-commands stop,dump
./as.sh --select math-game
./as.sh --repo-mirror aliyun --use-http ./as.sh --repo-mirror aliyun --use-http
WIKI: WIKI:
https://arthas.aliyun.com/doc https://arthas.aliyun.com/doc
@ -461,6 +485,33 @@ find_listen_port_process()
fi fi
} }
getTargetIPOrDefault()
{
local targetIP=${DEFAULT_TARGET_IP}
if [ "${TARGET_IP}" ]; then
targetIP=${TARGET_IP}
fi
echo $targetIP
}
getTelnetPortOrDefault()
{
local telnetPort=${DEFAULT_TELNET_PORT}
if [ "${TELNET_PORT}" ]; then
telnetPort=${TELNET_PORT}
fi
echo $telnetPort
}
getHttpPortOrDefault()
{
local httpPort=${DEFAULT_HTTP_PORT}
if [ "${HTTP_PORT}" ]; then
httpPort=${HTTP_PORT}
fi
echo $httpPort
}
# Status from com.taobao.arthas.client.TelnetConsole # Status from com.taobao.arthas.client.TelnetConsole
# Execute commands timeout # Execute commands timeout
STATUS_EXEC_TIMEOUT=100 STATUS_EXEC_TIMEOUT=100
@ -479,8 +530,8 @@ find_listen_port_process_by_client()
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \ "${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-client.jar" \ -jar "${arthas_lib_dir}/arthas-client.jar" \
${TARGET_IP} \ $(getTargetIPOrDefault) \
${TELNET_PORT} \ $(getTelnetPortOrDefault) \
-c "session" \ -c "session" \
--execution-timeout 2000 \ --execution-timeout 2000 \
2>&1 2>&1
@ -567,6 +618,26 @@ parse_arguments()
shift # past argument shift # past argument
shift # past value shift # past value
;; ;;
--app-name)
APP_NAME="$2"
shift # past argument
shift # past value
;;
--username)
USERNAME="$2"
shift # past argument
shift # past value
;;
--password)
PASSWORD="$2"
shift # past argument
shift # past value
;;
--disabled-commands)
DISABLED_COMMANDS="$2"
shift # past argument
shift # past value
;;
--use-http) --use-http)
USE_HTTP=true USE_HTTP=true
shift # past argument shift # past argument
@ -637,16 +708,18 @@ parse_arguments()
# check telnet port/http port # check telnet port/http port
local telnetPortPid local telnetPortPid
local httpPortPid local httpPortPid
if [[ $TELNET_PORT > 0 ]]; then local telnetPortOrDefault=$(getTelnetPortOrDefault)
telnetPortPid=$(find_listen_port_process $TELNET_PORT) local httpPortOrDefault=$(getHttpPortOrDefault)
if [[ $telnetPortOrDefault > 0 ]]; then
telnetPortPid=$(find_listen_port_process $telnetPortOrDefault)
if [ $telnetPortPid ]; then if [ $telnetPortPid ]; then
echo "[INFO] Process $telnetPortPid already using port $TELNET_PORT" echo "[INFO] Process $telnetPortPid already using port $telnetPortOrDefault"
fi fi
fi fi
if [[ $HTTP_PORT > 0 ]]; then if [[ $httpPortOrDefault > 0 ]]; then
httpPortPid=$(find_listen_port_process $HTTP_PORT) httpPortPid=$(find_listen_port_process $httpPortOrDefault)
if [ $telnetPortPid ]; then if [ $telnetPortPid ]; then
echo "[INFO] Process $httpPortPid already using port $HTTP_PORT" echo "[INFO] Process $httpPortPid already using port $httpPortOrDefault"
fi fi
fi fi
@ -668,7 +741,7 @@ parse_arguments()
fi fi
# check pid # check pid
if [ -z ${TARGET_PID} ] && [ ${BATCH_MODE} = false ]; then if [ -z ${TARGET_PID} ]; then
# interactive mode # interactive mode
local IFS=$'\n' local IFS=$'\n'
CANDIDATES=($(call_jps | grep -v sun.tools.jps.Jps | awk '{print $0}')) CANDIDATES=($(call_jps | grep -v sun.tools.jps.Jps | awk '{print $0}'))
@ -717,7 +790,7 @@ parse_arguments()
exit 1 exit 1
fi fi
if [[ ($httpPortPid) && ($TARGET_PID != $httpPortPid) ]]; then if [[ ($httpPortPid) && ($TARGET_PID != $httpPortPid) ]]; then
echo "Target process $TARGET_PID is not the process using port $HTTP_PORT, you will connect to an unexpected process." echo "Target process $TARGET_PID is not the process using port $(getHttpPortOrDefault), you will connect to an unexpected process."
echo "1. Try to restart as.sh, select process $httpPortPid, shutdown it first with running the 'stop' command." echo "1. Try to restart as.sh, select process $httpPortPid, shutdown it first with running the 'stop' command."
echo "2. Try to use different http port, for example: as.sh --telnet-port 9998 --http-port 9999" echo "2. Try to use different http port, for example: as.sh --telnet-port 9998 --http-port 9999"
exit 1 exit 1
@ -759,14 +832,47 @@ attach_jvm()
tempArgs+=("${STAT_URL}") tempArgs+=("${STAT_URL}")
fi fi
if [ "${APP_NAME}" ]; then
tempArgs+=("-app-name")
tempArgs+=("${APP_NAME}")
fi
if [ "${USERNAME}" ]; then
tempArgs+=("-username")
tempArgs+=("${USERNAME}")
fi
if [ "${PASSWORD}" ]; then
tempArgs+=("-password")
tempArgs+=("${PASSWORD}")
fi
if [ "${DISABLED_COMMANDS}" ]; then
tempArgs+=("-disabled-commands")
tempArgs+=("${DISABLED_COMMANDS}")
fi
if [ "${TARGET_IP}" ]; then
tempArgs+=("-target-ip")
tempArgs+=("${TARGET_IP}")
fi
if [ "${TELNET_PORT}" ]; then
tempArgs+=("-telnet-port")
tempArgs+=("${TELNET_PORT}")
fi
if [ "${HTTP_PORT}" ]; then
tempArgs+=("-http-port")
tempArgs+=("${HTTP_PORT}")
fi
if [ "${SESSION_TIMEOUT}" ]; then
tempArgs+=("-session-timeout")
tempArgs+=("${SESSION_TIMEOUT}")
fi
"${java_command[@]}" \ "${java_command[@]}" \
${ARTHAS_OPTS} ${JVM_OPTS} \ ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-core.jar" \ -jar "${arthas_lib_dir}/arthas-core.jar" \
-pid ${TARGET_PID} \ -pid ${TARGET_PID} \
-target-ip ${TARGET_IP} \
-telnet-port ${TELNET_PORT} \
-http-port ${HTTP_PORT} \
-session-timeout ${SESSION_TIMEOUT} \
"${tempArgs[@]}" \ "${tempArgs[@]}" \
-core "${arthas_lib_dir}/arthas-core.jar" \ -core "${arthas_lib_dir}/arthas-core.jar" \
-agent "${arthas_lib_dir}/arthas-agent.jar" -agent "${arthas_lib_dir}/arthas-agent.jar"
@ -811,7 +917,7 @@ sanity_check() {
} }
port_pid_check() { port_pid_check() {
if [[ $TELNET_PORT > 0 ]]; then if [[ $(getTelnetPortOrDefault) > 0 ]]; then
local telnet_output local telnet_output
local find_process_status local find_process_status
# declare local var before var=$() # declare local var before var=$()
@ -844,15 +950,15 @@ port_pid_check() {
} }
print_telnet_port_pid_error() { print_telnet_port_pid_error() {
echo "[ERROR] The telnet port $TELNET_PORT is used by process $telnetPortPid instead of target process $TARGET_PID, you will connect to an unexpected process." echo "[ERROR] The telnet port $(getTelnetPortOrDefault) is used by process $telnetPortPid instead of target process $TARGET_PID, you will connect to an unexpected process."
echo "[ERROR] 1. Try to restart as.sh, select process $telnetPortPid, shutdown it first with running the 'stop' command." echo "[ERROR] 1. Try to restart as.sh, select process $telnetPortPid, shutdown it first with running the 'stop' command."
echo "[ERROR] 2. Try to stop the existing arthas instance: java -jar arthas-client.jar 127.0.0.1 $TELNET_PORT -c \"stop\"" echo "[ERROR] 2. Try to stop the existing arthas instance: java -jar arthas-client.jar 127.0.0.1 $(getTelnetPortOrDefault) -c \"stop\""
echo "[ERROR] 3. Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1" echo "[ERROR] 3. Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1"
} }
print_telnet_port_used_error() { print_telnet_port_used_error() {
local error_msg=$1 local error_msg=$1
echo "[ERROR] The telnet port $TELNET_PORT is used, but process $error_msg, you will connect to an unexpected process." echo "[ERROR] The telnet port $(getTelnetPortOrDefault) is used, but process $error_msg, you will connect to an unexpected process."
echo "[ERROR] Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1" echo "[ERROR] Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1"
} }
@ -881,16 +987,16 @@ active_console()
if [ "${COMMAND}" ] ; then if [ "${COMMAND}" ] ; then
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \ "${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-client.jar" \ -jar "${arthas_lib_dir}/arthas-client.jar" \
${TARGET_IP} \ $(getTargetIPOrDefault) \
${TELNET_PORT} \ $(getTelnetPortOrDefault) \
"${tempArgs[@]}" \ "${tempArgs[@]}" \
-c "${COMMAND}" -c "${COMMAND}"
fi fi
if [ "${BATCH_FILE}" ] ; then if [ "${BATCH_FILE}" ] ; then
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \ "${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-client.jar" \ -jar "${arthas_lib_dir}/arthas-client.jar" \
${TARGET_IP} \ $(getTargetIPOrDefault) \
${TELNET_PORT} \ $(getTelnetPortOrDefault) \
"${tempArgs[@]}" \ "${tempArgs[@]}" \
-f ${BATCH_FILE} -f ${BATCH_FILE}
fi fi
@ -899,12 +1005,12 @@ active_console()
if [[ $(command -v telnet) == *"system32"* ]] ; then if [[ $(command -v telnet) == *"system32"* ]] ; then
# Windows/system32/telnet.exe can not run in Cygwin/MinGw # Windows/system32/telnet.exe can not run in Cygwin/MinGw
echo "It seems that current bash is under Windows. $(command -v telnet) can not run under bash." echo "It seems that current bash is under Windows. $(command -v telnet) can not run under bash."
echo "Please start cmd.exe from Windows start menu, and then run telnet ${TARGET_IP} ${TELNET_PORT} to connect to target process." echo "Please start cmd.exe from Windows start menu, and then run telnet $(getTargetIPOrDefault) $(getTelnetPortOrDefault) to connect to target process."
echo "Or visit http://127.0.0.1:${HTTP_PORT} to connect to target process." echo "Or visit http://127.0.0.1:$(getHttpPortOrDefault) to connect to target process."
return 1 return 1
fi fi
echo "telnet connecting to arthas server... current timestamp is `date +%s`" echo "telnet connecting to arthas server... current timestamp is `date +%s`"
telnet ${TARGET_IP} ${TELNET_PORT} telnet $(getTargetIPOrDefault) $(getTelnetPortOrDefault)
else else
echo "'telnet' is required." 1>&2 echo "'telnet' is required." 1>&2
return 1 return 1

@ -1,10 +1,10 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>com.taobao.arthas</groupId> <groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId> <artifactId>arthas-all</artifactId>
<version>3.4.4-SNAPSHOT</version> <version>${revision}</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<artifactId>arthas-boot</artifactId> <artifactId>arthas-boot</artifactId>

@ -1,5 +1,8 @@
package com.taobao.arthas.boot; package com.taobao.arthas.boot;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_ERROR;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -11,12 +14,12 @@ import java.security.CodeSource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.InputMismatchException;
import java.util.List; import java.util.List;
import java.util.Scanner; import java.util.Scanner;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.InputMismatchException;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
@ -36,9 +39,6 @@ import com.taobao.middleware.cli.annotations.Name;
import com.taobao.middleware.cli.annotations.Option; import com.taobao.middleware.cli.annotations.Option;
import com.taobao.middleware.cli.annotations.Summary; import com.taobao.middleware.cli.annotations.Summary;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_ERROR;
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT;
/** /**
* @author hengyunabc 2018-10-26 * @author hengyunabc 2018-10-26
* *
@ -47,15 +47,17 @@ import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT;
@Summary("Bootstrap Arthas") @Summary("Bootstrap Arthas")
@Description("EXAMPLES:\n" + " java -jar arthas-boot.jar <pid>\n" + " java -jar arthas-boot.jar --target-ip 0.0.0.0\n" @Description("EXAMPLES:\n" + " java -jar arthas-boot.jar <pid>\n" + " java -jar arthas-boot.jar --target-ip 0.0.0.0\n"
+ " java -jar arthas-boot.jar --telnet-port 9999 --http-port -1\n" + " java -jar arthas-boot.jar --telnet-port 9999 --http-port -1\n"
+ " java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'\n" + " java -jar arthas-boot.jar --username admin --password <password>\n"
+ " java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws' --app-name demoapp\n"
+ " java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws' --agent-id bvDOe8XbTM2pQWjF4cfw\n" + " java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws' --agent-id bvDOe8XbTM2pQWjF4cfw\n"
+ " java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'\n" + " java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'\n"
+ " java -jar arthas-boot.jar -c 'sysprop; thread' <pid>\n" + " java -jar arthas-boot.jar -c 'sysprop; thread' <pid>\n"
+ " java -jar arthas-boot.jar -f batch.as <pid>\n" + " java -jar arthas-boot.jar -f batch.as <pid>\n"
+ " java -jar arthas-boot.jar --use-version 3.4.3\n" + " java -jar arthas-boot.jar --use-version 3.5.2\n"
+ " java -jar arthas-boot.jar --versions\n" + " java -jar arthas-boot.jar --versions\n"
+ " java -jar arthas-boot.jar --select arthas-demo\n" + " java -jar arthas-boot.jar --select math-game\n"
+ " java -jar arthas-boot.jar --session-timeout 3600\n" + " java -jar arthas-boot.jar --attach-only\n" + " java -jar arthas-boot.jar --session-timeout 3600\n" + " java -jar arthas-boot.jar --attach-only\n"
+ " java -jar arthas-boot.jar --disabled-commands stop,dump\n"
+ " java -jar arthas-boot.jar --repo-mirror aliyun --use-http\n" + "WIKI:\n" + " java -jar arthas-boot.jar --repo-mirror aliyun --use-http\n" + "WIKI:\n"
+ " https://arthas.aliyun.com/doc\n") + " https://arthas.aliyun.com/doc\n")
public class Bootstrap { public class Bootstrap {
@ -67,9 +69,9 @@ public class Bootstrap {
private boolean help = false; private boolean help = false;
private long pid = -1; private long pid = -1;
private String targetIp = DEFAULT_TARGET_IP; private String targetIp;
private int telnetPort = DEFAULT_TELNET_PORT; private Integer telnetPort;
private int httpPort = DEFAULT_HTTP_PORT; private Integer httpPort;
/** /**
* @see com.taobao.arthas.core.config.Configure#DEFAULT_SESSION_TIMEOUT_SECONDS * @see com.taobao.arthas.core.config.Configure#DEFAULT_SESSION_TIMEOUT_SECONDS
*/ */
@ -118,13 +120,26 @@ public class Bootstrap {
private String tunnelServer; private String tunnelServer;
private String agentId; private String agentId;
private String appName;
private String username;
private String password;
private String statUrl; private String statUrl;
private String select; private String select;
private String disabledCommands;
static { static {
ARTHAS_LIB_DIR = new File( String arthasLibDirEnv = System.getenv("ARTHAS_LIB_DIR");
System.getProperty("user.home") + File.separator + ".arthas" + File.separator + "lib"); if (arthasLibDirEnv != null) {
ARTHAS_LIB_DIR = new File(arthasLibDirEnv);
} else {
ARTHAS_LIB_DIR = new File(
System.getProperty("user.home") + File.separator + ".arthas" + File.separator + "lib");
}
try { try {
ARTHAS_LIB_DIR.mkdirs(); ARTHAS_LIB_DIR.mkdirs();
} catch (Throwable t) { } catch (Throwable t) {
@ -258,6 +273,23 @@ public class Bootstrap {
this.agentId = agentId; this.agentId = agentId;
} }
@Option(longName = "app-name")
@Description("The app name")
public void setAppName(String appName) {
this.appName = appName;
}
@Option(longName = "username")
@Description("The username")
public void setUsername(String username) {
this.username = username;
}
@Option(longName = "password")
@Description("The password")
public void setPassword(String password) {
this.password = password;
}
@Option(longName = "stat-url") @Option(longName = "stat-url")
@Description("The report stat url") @Description("The report stat url")
public void setStatUrl(String statUrl) { public void setStatUrl(String statUrl) {
@ -270,6 +302,12 @@ public class Bootstrap {
this.select = select; this.select = select;
} }
@Option(longName = "disabled-commands")
@Description("disable some commands ")
public void setDisabledCommands(String disabledCommands) {
this.disabledCommands = disabledCommands;
}
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException,
ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException { IllegalArgumentException, InvocationTargetException {
@ -325,16 +363,16 @@ public class Bootstrap {
// check telnet/http port // check telnet/http port
long telnetPortPid = -1; long telnetPortPid = -1;
long httpPortPid = -1; long httpPortPid = -1;
if (bootstrap.getTelnetPort() > 0) { if (bootstrap.getTelnetPortOrDefault() > 0) {
telnetPortPid = SocketUtils.findTcpListenProcess(bootstrap.getTelnetPort()); telnetPortPid = SocketUtils.findTcpListenProcess(bootstrap.getTelnetPortOrDefault());
if (telnetPortPid > 0) { if (telnetPortPid > 0) {
AnsiLog.info("Process {} already using port {}", telnetPortPid, bootstrap.getTelnetPort()); AnsiLog.info("Process {} already using port {}", telnetPortPid, bootstrap.getTelnetPortOrDefault());
} }
} }
if (bootstrap.getHttpPort() > 0) { if (bootstrap.getHttpPortOrDefault() > 0) {
httpPortPid = SocketUtils.findTcpListenProcess(bootstrap.getHttpPort()); httpPortPid = SocketUtils.findTcpListenProcess(bootstrap.getHttpPortOrDefault());
if (httpPortPid > 0) { if (httpPortPid > 0) {
AnsiLog.info("Process {} already using port {}", httpPortPid, bootstrap.getHttpPort()); AnsiLog.info("Process {} already using port {}", httpPortPid, bootstrap.getHttpPortOrDefault());
} }
} }
@ -357,7 +395,7 @@ public class Bootstrap {
if (httpPortPid > 0 && pid != httpPortPid) { if (httpPortPid > 0 && pid != httpPortPid) {
AnsiLog.error("Target process {} is not the process using port {}, you will connect to an unexpected process.", AnsiLog.error("Target process {} is not the process using port {}, you will connect to an unexpected process.",
pid, bootstrap.getHttpPort()); pid, bootstrap.getHttpPortOrDefault());
AnsiLog.error("1. Try to restart arthas-boot, select process {}, shutdown it first with running the 'stop' command.", AnsiLog.error("1. Try to restart arthas-boot, select process {}, shutdown it first with running the 'stop' command.",
httpPortPid); httpPortPid);
AnsiLog.error("2. Or try to use different http port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port 9999", httpPortPid); AnsiLog.error("2. Or try to use different http port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port 9999", httpPortPid);
@ -461,10 +499,10 @@ public class Bootstrap {
AnsiLog.info("arthas home: " + arthasHomeDir); AnsiLog.info("arthas home: " + arthasHomeDir);
if (telnetPortPid > 0 && pid == telnetPortPid) { if (telnetPortPid > 0 && pid == telnetPortPid) {
AnsiLog.info("The target process already listen port {}, skip attach.", bootstrap.getTelnetPort()); AnsiLog.info("The target process already listen port {}, skip attach.", bootstrap.getTelnetPortOrDefault());
} else { } else {
//double check telnet port and pid before attach //double check telnet port and pid before attach
telnetPortPid = findProcessByTelnetClient(arthasHomeDir.getAbsolutePath(), bootstrap.getTelnetPort()); telnetPortPid = findProcessByTelnetClient(arthasHomeDir.getAbsolutePath(), bootstrap.getTelnetPortOrDefault());
checkTelnetPortPid(bootstrap, telnetPortPid, pid); checkTelnetPortPid(bootstrap, telnetPortPid, pid);
// start arthas-core.jar // start arthas-core.jar
@ -473,12 +511,21 @@ public class Bootstrap {
attachArgs.add(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath()); attachArgs.add(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath());
attachArgs.add("-pid"); attachArgs.add("-pid");
attachArgs.add("" + pid); attachArgs.add("" + pid);
attachArgs.add("-target-ip"); if (bootstrap.getTargetIp() != null) {
attachArgs.add(bootstrap.getTargetIp()); attachArgs.add("-target-ip");
attachArgs.add("-telnet-port"); attachArgs.add(bootstrap.getTargetIp());
attachArgs.add("" + bootstrap.getTelnetPort()); }
attachArgs.add("-http-port");
attachArgs.add("" + bootstrap.getHttpPort()); if (bootstrap.getTelnetPort() != null) {
attachArgs.add("-telnet-port");
attachArgs.add("" + bootstrap.getTelnetPort());
}
if (bootstrap.getHttpPort() != null) {
attachArgs.add("-http-port");
attachArgs.add("" + bootstrap.getHttpPort());
}
attachArgs.add("-core"); attachArgs.add("-core");
attachArgs.add(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath()); attachArgs.add(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath());
attachArgs.add("-agent"); attachArgs.add("-agent");
@ -488,6 +535,20 @@ public class Bootstrap {
attachArgs.add("" + bootstrap.getSessionTimeout()); attachArgs.add("" + bootstrap.getSessionTimeout());
} }
if (bootstrap.getAppName() != null) {
attachArgs.add("-app-name");
attachArgs.add(bootstrap.getAppName());
}
if (bootstrap.getUsername() != null) {
attachArgs.add("-username");
attachArgs.add(bootstrap.getUsername());
}
if (bootstrap.getPassword() != null) {
attachArgs.add("-password");
attachArgs.add(bootstrap.getPassword());
}
if (bootstrap.getTunnelServer() != null) { if (bootstrap.getTunnelServer() != null) {
attachArgs.add("-tunnel-server"); attachArgs.add("-tunnel-server");
attachArgs.add(bootstrap.getTunnelServer()); attachArgs.add(bootstrap.getTunnelServer());
@ -501,6 +562,11 @@ public class Bootstrap {
attachArgs.add(bootstrap.getStatUrl()); attachArgs.add(bootstrap.getStatUrl());
} }
if (bootstrap.getDisabledCommands() != null){
attachArgs.add("-disabled-commands");
attachArgs.add(bootstrap.getDisabledCommands());
}
AnsiLog.info("Try to attach process " + pid); AnsiLog.info("Try to attach process " + pid);
AnsiLog.debug("Start arthas-core.jar args: " + attachArgs); AnsiLog.debug("Start arthas-core.jar args: " + attachArgs);
ProcessUtils.startArthasCore(pid, attachArgs); ProcessUtils.startArthasCore(pid, attachArgs);
@ -538,10 +604,10 @@ public class Bootstrap {
} }
// telnet port ,ip // telnet port ,ip
telnetArgs.add(bootstrap.getTargetIp()); telnetArgs.add(bootstrap.getTargetIpOrDefault());
telnetArgs.add("" + bootstrap.getTelnetPort()); telnetArgs.add("" + bootstrap.getTelnetPortOrDefault());
AnsiLog.info("arthas-client connect {} {}", bootstrap.getTargetIp(), bootstrap.getTelnetPort()); AnsiLog.info("arthas-client connect {} {}", bootstrap.getTargetIpOrDefault(), bootstrap.getTelnetPortOrDefault());
AnsiLog.debug("Start arthas-client.jar args: " + telnetArgs); AnsiLog.debug("Start arthas-client.jar args: " + telnetArgs);
// fix https://github.com/alibaba/arthas/issues/833 // fix https://github.com/alibaba/arthas/issues/833
@ -552,10 +618,10 @@ public class Bootstrap {
private static void checkTelnetPortPid(Bootstrap bootstrap, long telnetPortPid, long targetPid) { private static void checkTelnetPortPid(Bootstrap bootstrap, long telnetPortPid, long targetPid) {
if (telnetPortPid > 0 && targetPid != telnetPortPid) { if (telnetPortPid > 0 && targetPid != telnetPortPid) {
AnsiLog.error("The telnet port {} is used by process {} instead of target process {}, you will connect to an unexpected process.", AnsiLog.error("The telnet port {} is used by process {} instead of target process {}, you will connect to an unexpected process.",
bootstrap.getTelnetPort(), telnetPortPid, targetPid); bootstrap.getTelnetPortOrDefault(), telnetPortPid, targetPid);
AnsiLog.error("1. Try to restart arthas-boot, select process {}, shutdown it first with running the 'stop' command.", AnsiLog.error("1. Try to restart arthas-boot, select process {}, shutdown it first with running the 'stop' command.",
telnetPortPid); telnetPortPid);
AnsiLog.error("2. Or try to stop the existing arthas instance: java -jar arthas-client.jar 127.0.0.1 {} -c \"stop\"", bootstrap.getTelnetPort()); AnsiLog.error("2. Or try to stop the existing arthas instance: java -jar arthas-client.jar 127.0.0.1 {} -c \"stop\"", bootstrap.getTelnetPortOrDefault());
AnsiLog.error("3. Or try to use different telnet port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port -1"); AnsiLog.error("3. Or try to use different telnet port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port -1");
System.exit(1); System.exit(1);
} }
@ -704,14 +770,38 @@ public class Bootstrap {
return targetIp; return targetIp;
} }
public int getTelnetPort() { public String getTargetIpOrDefault() {
if (this.targetIp == null) {
return DEFAULT_TARGET_IP;
} else {
return this.targetIp;
}
}
public Integer getTelnetPort() {
return telnetPort; return telnetPort;
} }
public int getTelnetPortOrDefault() {
if (this.telnetPort == null) {
return DEFAULT_TELNET_PORT;
} else {
return this.telnetPort;
}
}
public int getHttpPort() { public Integer getHttpPort() {
return httpPort; return httpPort;
} }
public int getHttpPortOrDefault() {
if (this.httpPort == null) {
return DEFAULT_HTTP_PORT;
} else {
return this.httpPort;
}
}
public String getCommand() { public String getCommand() {
return command; return command;
} }
@ -760,6 +850,10 @@ public class Bootstrap {
return agentId; return agentId;
} }
public String getAppName() {
return appName;
}
public String getStatUrl() { public String getStatUrl() {
return statUrl; return statUrl;
} }
@ -767,4 +861,16 @@ public class Bootstrap {
public String getSelect() { public String getSelect() {
return select; return select;
} }
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getDisabledCommands() {
return disabledCommands;
}
} }

@ -65,7 +65,7 @@ public class ProcessUtils {
} }
if (processMap.isEmpty()) { if (processMap.isEmpty()) {
AnsiLog.info("Can not find java process. Try to pass <pid> in command line."); AnsiLog.info("Can not find java process. Try to run `jps` command lists the instrumented Java HotSpot VMs on the target system.");
return -1; return -1;
} }
@ -233,13 +233,13 @@ public class ProcessUtils {
String javaHome = findJavaHome(); String javaHome = findJavaHome();
// find java/java.exe // find java/java.exe
File javaPath = findJava(); File javaPath = findJava(javaHome);
if (javaPath == null) { if (javaPath == null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Can not find java/java.exe executable file under java home: " + javaHome); "Can not find java/java.exe executable file under java home: " + javaHome);
} }
File toolsJar = findToolsJar(); File toolsJar = findToolsJar(javaHome);
if (JavaVersionUtils.isLessThanJava9()) { if (JavaVersionUtils.isLessThanJava9()) {
if (toolsJar == null || !toolsJar.exists()) { if (toolsJar == null || !toolsJar.exists()) {
@ -313,8 +313,8 @@ public class ProcessUtils {
// find arthas-client.jar // find arthas-client.jar
URLClassLoader classLoader = new URLClassLoader( URLClassLoader classLoader = new URLClassLoader(
new URL[]{new File(arthasHomeDir, "arthas-client.jar").toURI().toURL()}); new URL[]{new File(arthasHomeDir, "arthas-client.jar").toURI().toURL()});
Class<?> telnetConsoleClas = classLoader.loadClass("com.taobao.arthas.client.TelnetConsole"); Class<?> telnetConsoleClass = classLoader.loadClass("com.taobao.arthas.client.TelnetConsole");
Method processMethod = telnetConsoleClas.getMethod("process", String[].class); Method processMethod = telnetConsoleClass.getMethod("process", String[].class);
//redirect System.out/System.err //redirect System.out/System.err
PrintStream originSysOut = System.out; PrintStream originSysOut = System.out;
@ -354,8 +354,7 @@ public class ProcessUtils {
} }
} }
private static File findJava() { private static File findJava(String javaHome) {
String javaHome = findJavaHome();
String[] paths = { "bin/java", "bin/java.exe", "../bin/java", "../bin/java.exe" }; String[] paths = { "bin/java", "bin/java.exe", "../bin/java", "../bin/java.exe" };
List<File> javaList = new ArrayList<File>(); List<File> javaList = new ArrayList<File>();
@ -389,12 +388,11 @@ public class ProcessUtils {
return javaList.get(0); return javaList.get(0);
} }
private static File findToolsJar() { private static File findToolsJar(String javaHome) {
if (JavaVersionUtils.isGreaterThanJava8()) { if (JavaVersionUtils.isGreaterThanJava8()) {
return null; return null;
} }
String javaHome = findJavaHome();
File toolsJar = new File(javaHome, "lib/tools.jar"); File toolsJar = new File(javaHome, "lib/tools.jar");
if (!toolsJar.exists()) { if (!toolsJar.exists()) {
toolsJar = new File(javaHome, "../lib/tools.jar"); toolsJar = new File(javaHome, "../lib/tools.jar");

@ -3,6 +3,8 @@ package com.taobao.arthas.boot;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Rule; import org.junit.Rule;
@ -29,13 +31,16 @@ public class DownloadUtilsTest {
@Test @Test
public void testAliyunDownload() throws IOException { public void testAliyunDownload() throws IOException {
String version = "3.3.7"; // fix travis-ci failed problem
File folder = rootFolder.newFolder(); if (TimeUnit.MILLISECONDS.toHours(TimeZone.getDefault().getOffset(System.currentTimeMillis())) == 8) {
System.err.println(folder.getAbsolutePath()); String version = "3.3.7";
DownloadUtils.downArthasPackaging("aliyun", false, version, folder.getAbsolutePath()); File folder = rootFolder.newFolder();
System.err.println(folder.getAbsolutePath());
File as = new File(folder, version + File.separator + "arthas" + File.separator + "as.sh"); DownloadUtils.downArthasPackaging("aliyun", false, version, folder.getAbsolutePath());
Assert.assertTrue(as.exists());
File as = new File(folder, version + File.separator + "arthas" + File.separator + "as.sh");
Assert.assertTrue(as.exists());
}
} }
@Test @Test

@ -1,222 +0,0 @@
## ByteKit
## 目标
1. 之前的Arthas里的字节码增强是通过asm来处理的代码逻辑不好修改理解困难
1. 基于ASM提供更高层的字节码处理能力面向诊断/APM领域不是通用的字节码库
1. ByteKit期望能提供一套简洁的API让开发人员可以比较轻松的完成字节码增强
## 对比
| 功能 | 函数Enter/Exit注入点 | 绑定数据 | inline | 防止重复增强 | 避免装箱/拆箱开销 |origin调用替换 | `@ExceptionHandler` |
| ---- | ---- |---- | :----: |:----: | :----: |:----: | :----: |
| ByteKit | `@AtEnter` <br> `@AtExit` <br>`@AtExceptionExit` <br> `@AtFieldAccess` <br> `@AtInvoke`<br>`@AtInvokeException`<br>`@AtLine`<br>`@AtSyncEnter`<br>`@AtSyncExit`<br>`@AtThrow`| this/args/return/throw<br>field<br>locals<br>子调用入参/返回值/子调用异常<br>line number|✓|✓|✓|✓|✓|
| ByteBuddy | `OnMethodEnter`<br>`@OnMethodExit`<br> `@OnMethodExit#onThrowable()`| this/args/return/throw<br>field<br>locals|✓|✗|✓|✓|✓|
| 传统AOP | `Enter`<br>`Exit`<br>`Exception` |this/args/return/throw|✗|✗|✗|✗|✗
## 特性
### 1. 丰富的注入点支持
* `@AtEnter` 函数入口
* `@AtExit` 函数退出
* `@AtExceptionExit` 函数抛出异常
* `@AtFieldAccess` 访问field
* `@AtInvoke` 在method里的子函数调用
* `@AtInvokeException` 在method里的子函数调用抛出异常
* `@AtLine` 在指定行号
* `@AtSyncEnter` 进入同步块,比如`synchronized`块
* `@AtSyncExit` 退出同步块
* `@AtThrow` 代码里显式`throw`异常点
### 2. 动态的Binding
* `@Binding.This` this对象
* `@@Binding.Class` Class对象
* `@Binding.Method` 函数调用的 Method 对象
* `@Binding.MethodName` 函数的名字
* `@Binding.MethodDesc` 函数的desc
* `@Binding.Return` 函数调用的返回值
* `@Binding.Throwable` 函数里抛出的异常
* `@Binding.Args` 函数调用的入参
* `@Binding.ArgNames` 函数调用的入参的名字
* `@Binding.LocalVars` 局部变量
* `@Binding.LocalVarNames` 局部变量的名字
* `@Binding.Field` field对象属性字段
* `@Binding.InvokeArgs` method里的子函数调用的入参
* `@Binding.InvokeReturn` method里的子函数调用的返回值
* `@Binding.InvokeMethodName` method里的子函数调用的名字
* `@Binding.InvokeMethodOwner` method里的子函数调用的类名
* `@Binding.InvokeMethodDeclaration` method里的子函数调用的desc
* `@Binding.Line` 行号
* `@Binding.Monitor` 同步块里监控的对象
### 3. 可编程的异常处理
* `@ExceptionHandler` 在插入的增强代码,可以用`try/catch`块包围起来
### 4. inline支持
增强的代码 和 异常处理代码都可以通过 inline技术内联到原来的类里达到最理想的增强效果。
### 5. invokeOrigin 技术
通常我们要增强一个类就想要办法在函数前后插入一个static的回调函数但这样子局限太大。那么有没有更灵活的方式呢
比如有一个 hello() 函数:
```java
public String hello(String str) {
return "hello " + str;
}
```
我们想对它做增强,那么可以编写下面的代码:
```java
public String hello(String str) {
System.out.println("before");
Object value = InstrumentApi.invokeOrigin();
System.out.println("after, result: " + value);
return object;
}
```
增强后的结果是:
```java
public String hello(String str) {
System.out.println("before");
Object value = "hello " + str;
System.out.println("after, result: " + value);
return object;
}
```
**这种方式可以随意插入代码,非常灵活。**
## 示例
以`ByteKitDemo.java`为例说明,[[查看源文件](src/test/java/com/example/ByteKitDemo.java)]。
### 1. 定义注入点和Binding数据
* 在下面的 SampleInterceptor 时定义了要注入 `@AtEnter`/`@AtExit`/`@AtExceptionExit`三个地方,
* 用`@Binding`绑定了不同的数据
* 在`@AtEnter`里配置了 `inline = true`,则说明插入的`SampleInterceptor#atEnter`函数本身会被inline掉
* 配置了 `suppress = RuntimeException.class``suppressHandler = PrintExceptionSuppressHandler.class`,说明插入的代码会被 `try/catch` 包围
```java
public static class SampleInterceptor {
@AtEnter(inline = true, suppress = RuntimeException.class, suppressHandler = PrintExceptionSuppressHandler.class)
public static void atEnter(@Binding.This Object object,
@Binding.Class Object clazz,
@Binding.Args Object[] args,
@Binding.MethodName String methodName,
@Binding.MethodDesc String methodDesc) {
System.out.println("atEnter, args[0]: " + args[0]);
}
@AtExit(inline = true)
public static void atExit(@Binding.Return Object returnObject) {
System.out.println("atExit, returnObject: " + returnObject);
}
@AtExceptionExit(inline = true, onException = RuntimeException.class)
public static void atExceptionExit(@Binding.Throwable RuntimeException ex,
@Binding.Field(name = "exceptionCount") int exceptionCount) {
System.out.println("atExceptionExit, ex: " + ex.getMessage() + ", field exceptionCount: " + exceptionCount);
}
}
```
### 2. @ExceptionHandler
在上面的 `@AtEnter`配置里,生成的代码会被 try/catch 包围,那么具体的内容是在`PrintExceptionSuppressHandler`里
```java
public static class PrintExceptionSuppressHandler {
@ExceptionHandler(inline = true)
public static void onSuppress(@Binding.Throwable Throwable e, @Binding.Class Object clazz) {
System.out.println("exception handler: " + clazz);
e.printStackTrace();
}
}
```
### 3. 查看反编译结果
原始的Sample类是
```java
public static class Sample {
private int exceptionCount = 0;
public String hello(String str, boolean exception) {
if (exception) {
exceptionCount++;
throw new RuntimeException("test exception, str: " + str);
}
return "hello " + str;
}
}
```
增强后的字节码,再反编译:
```java
package com.example;
public static class ByteKitDemo.Sample {
private int exceptionCount = 0;
public String hello(String string, boolean bl) {
try {
String string2 = "(Ljava/lang/String;Z)Ljava/lang/String;";
String string3 = "hello";
Object[] arrobject = new Object[]{string, new Boolean(bl)};
Class<ByteKitDemo.Sample> class_ = ByteKitDemo.Sample.class;
ByteKitDemo.Sample sample = this;
System.out.println("atEnter, args[0]: " + arrobject[0]);
}
catch (RuntimeException runtimeException) {
Class<ByteKitDemo.Sample> class_ = ByteKitDemo.Sample.class;
RuntimeException runtimeException2 = runtimeException;
System.out.println("exception handler: " + class_);
runtimeException2.printStackTrace();
}
try {
String string4;
void str;
void exception;
if (exception != false) {
++this.exceptionCount;
throw new RuntimeException("test exception, str: " + (String)str);
}
String string5 = string4 = "hello " + (String)str;
System.out.println("atExit, returnObject: " + string5);
return string4;
}
catch (RuntimeException runtimeException) {
int n = this.exceptionCount;
RuntimeException runtimeException3 = runtimeException;
System.out.println("atExceptionExit, ex: " + runtimeException3.getMessage() + ", field exceptionCount: " + n);
throw runtimeException;
}
}
}
```

@ -1,92 +0,0 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId>
<version>3.4.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>arthas-bytekit</artifactId>
<name>arthas-bytekit</name>
<dependencies>
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.arthas</groupId>
<artifactId>arthas-repackage-asm</artifactId>
</dependency>
<dependency>
<groupId>org.benf</groupId>
<artifactId>cfr</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<!-- Test Artifacts -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.5.9.RELEASE</version>
<scope>test</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-demo</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>arthas-bytekit</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF-8</encoding>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -1,22 +0,0 @@
package com.taobao.arthas.bytekit;
import java.util.List;
import com.taobao.arthas.bytekit.asm.interceptor.InterceptorProcessor;
import com.taobao.arthas.bytekit.asm.interceptor.parser.InterceptorClassParser;
import com.taobao.arthas.bytekit.asm.matcher.ClassMatcher;
import com.taobao.arthas.bytekit.asm.matcher.MethodMatcher;
public class ByteKit {
private ClassMatcher classMatcher;
private MethodMatcher methodMatcher;
private Class<?> interceptorClass;
private InterceptorClassParser interceptorClassParser;
private List<InterceptorProcessor> interceptorProcessors;
}

@ -1,56 +0,0 @@
package com.taobao.arthas.bytekit.asm;
import com.alibaba.arthas.deps.org.objectweb.asm.ClassReader;
import com.alibaba.arthas.deps.org.objectweb.asm.ClassWriter;
/**
* @author vlinux
* @author hengyunabc 2020-05-29
*
*/
public class ClassLoaderAwareClassWriter extends ClassWriter {
private ClassLoader classLoader;
public ClassLoaderAwareClassWriter(int flags, ClassLoader loader) {
this(null, flags, loader);
}
public ClassLoaderAwareClassWriter(ClassReader classReader, int flags, ClassLoader loader) {
super(classReader, flags);
this.classLoader = loader;
}
/*
*
* ClassWritergetCommonSuperClass使API
*
* getCommonSuperClass
*
* getCommonSuperClass() ClassLoader使ClassLoader
* Object.class.getClassLoader()
*/
@Override
protected String getCommonSuperClass(String type1, String type2) {
Class<?> c, d;
try {
c = Class.forName(type1.replace('/', '.'), false, classLoader);
d = Class.forName(type2.replace('/', '.'), false, classLoader);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (c.isAssignableFrom(d)) {
return type1;
}
if (d.isAssignableFrom(c)) {
return type2;
}
if (c.isInterface() || d.isInterface()) {
return "java/lang/Object";
} else {
do {
c = c.getSuperclass();
} while (!c.isAssignableFrom(d));
return c.getName().replace('.', '/');
}
}
}

@ -1,86 +0,0 @@
package com.taobao.arthas.bytekit.asm;
import com.alibaba.arthas.deps.org.objectweb.asm.Label;
import com.alibaba.arthas.deps.org.objectweb.asm.Opcodes;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.commons.LocalVariablesSorter;
/**
* Adapter for to be inlined code.
*
* This adapter does all parameter renaming and replacing of the RETURN opcodes
*
*
*/
public class InliningAdapter extends LocalVariablesSorter {
private final Label end;
private LocalVariablesSorter lvs;
public InliningAdapter(LocalVariablesSorter mv, int access, String desc, Label end) {
super(Opcodes.ASM9, access, desc, mv);
this.end = end;
this.lvs = mv;
// int off = (access & Opcodes.ACC_STATIC) != 0 ?
// 0 : 1;
// Type[] args = Type.getArgumentTypes(desc);
// for (int i = args.length - 1; i >= 0; i--) {
// super.visitVarInsn(args[i].getOpcode(
// Opcodes.ISTORE), i + off);
// }
// if (off > 0) {
// super.visitVarInsn(Opcodes.ASTORE, 0);
// }
// save args to local vars
int off = (access & Opcodes.ACC_STATIC) != 0 ? 0 : 1;
Type[] args = Type.getArgumentTypes(desc);
int argsOff = off;
for(int i = 0; i < args.length; ++i) {
argsOff += args[i].getSize();
}
for(int i = args.length - 1; i >= 0; --i) {
argsOff -= args[i].getSize();
this.visitVarInsn(args[i].getOpcode(Opcodes.ISTORE), argsOff);
}
// this
if (off > 0) {
this.visitVarInsn(Opcodes.ASTORE, 0);
}
}
@Override
public void visitInsn(int opcode) {
if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) {
super.visitJumpInsn(Opcodes.GOTO, end);
} else {
super.visitInsn(opcode);
}
}
@Override
public void visitMaxs(int stack, int locals) {
// super.visitMaxs(stack, locals);
}
@Override
protected int newLocalMapping(Type type) {
return lvs.newLocal(type);
}
@Override
public void visitVarInsn(int opcode, int var) {
super.visitVarInsn(opcode, var + this.firstLocal);
}
@Override
public void visitIincInsn(int var, int increment) {
super.visitIincInsn(var + this.firstLocal, increment);
}
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
super.visitLocalVariable(name, desc, signature, start, end, index + this.firstLocal);
}
}

@ -1,97 +0,0 @@
package com.taobao.arthas.bytekit.asm;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.arthas.deps.org.objectweb.asm.Label;
import com.alibaba.arthas.deps.org.objectweb.asm.MethodVisitor;
import com.alibaba.arthas.deps.org.objectweb.asm.Opcodes;
import com.alibaba.arthas.deps.org.objectweb.asm.commons.GeneratorAdapter;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodNode;
/**
* @author hengyunabc 2018-01-31
*
*/
public abstract class MethodCallInliner extends GeneratorAdapter {
public class CatchBlock {
private Label start;
private Label handler;
private String type;
private Label end;
public CatchBlock(Label start, Label end, Label handler, String type) {
this.start = start;
this.end = end;
this.handler = handler;
this.type = type;
}
}
private final MethodNode toBeInlined;
private List<CatchBlock> blocks = new ArrayList<CatchBlock>();
private boolean inlining;
private boolean afterInlining;
public MethodCallInliner(int access, String name, String desc, MethodVisitor mv,
MethodNode toBeInlined) {
super(Opcodes.ASM9, mv, access, name, desc);
this.toBeInlined = toBeInlined;
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (!shouldBeInlined(owner, name, desc)) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
// if (this.analyzerAdapter != null) {
// mv = new MergeFrameAdapter(this.api, this.analyzerAdapter,
// (MethodVisitor)mv);
// }
Label end = new Label();
inlining = true;
toBeInlined.instructions.resetLabels();
// pass the to be inlined method through the inlining adapter to this
toBeInlined.accept(new InliningAdapter(this, toBeInlined.access, toBeInlined.desc, end));
inlining = false;
afterInlining = true;
// visit the end label
super.visitLabel(end);
// box the return value if necessary
// Type returnType =
// Type.getMethodType(toBeInlined.desc).getReturnType();
// valueOf(returnType);
}
abstract boolean shouldBeInlined(String owner, String name, String desc);
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
if (!inlining) {
blocks.add(new CatchBlock(start, end, handler, type));
} else {
super.visitTryCatchBlock(start, end, handler, type);
}
}
@Override
public void visitMaxs(int stack, int locals) {
for (CatchBlock b : blocks)
super.visitTryCatchBlock(b.start, b.end, b.handler, b.type);
super.visitMaxs(stack, locals);
}
@Override
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
// swallow
}
}

@ -1,48 +0,0 @@
package com.taobao.arthas.bytekit.asm;
/**
*
* @author hengyunabc 2019-03-18
*
*/
public class MethodInfo {
private String owner;
private int access;
private String name;
private String desc;
public int getAccess() {
return access;
}
public void setAccess(int access) {
this.access = access;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
}

@ -1,784 +0,0 @@
package com.taobao.arthas.bytekit.asm;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import com.alibaba.arthas.deps.org.objectweb.asm.Opcodes;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.commons.Method;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.AbstractInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.ClassNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.FrameNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.IincInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.IntInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.JumpInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LabelNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LdcInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LocalVariableNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.TryCatchBlockNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.TypeInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.VarInsnNode;
import com.taobao.arthas.bytekit.asm.location.filter.DefaultLocationFilter;
import com.taobao.arthas.bytekit.asm.location.filter.LocationFilter;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
import com.taobao.arthas.bytekit.utils.AsmUtils;
public class MethodProcessor {
private String owner;
/**
* maybe null
*/
private ClassNode classNode;
private MethodNode methodNode;
private final Type[] argumentTypes;
private final Type returnType;
private int nextLocals;
private static final Type BYTE_TYPE = Type.getObjectType("java/lang/Byte");
private static final Type BOOLEAN_TYPE = Type.getObjectType("java/lang/Boolean");
private static final Type SHORT_TYPE = Type.getObjectType("java/lang/Short");
private static final Type CHARACTER_TYPE = Type.getObjectType("java/lang/Character");
private static final Type INTEGER_TYPE = Type.getObjectType("java/lang/Integer");
private static final Type FLOAT_TYPE = Type.getObjectType("java/lang/Float");
private static final Type LONG_TYPE = Type.getObjectType("java/lang/Long");
private static final Type DOUBLE_TYPE = Type.getObjectType("java/lang/Double");
private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
private static final Type STRING_TYPE = Type.getObjectType("java/lang/String");
private static final Type THROWABLE_TYPE = Type.getObjectType("java/lang/Throwable");
private static final Type NUMBER_TYPE = Type.getObjectType("java/lang/Number");
private static final Type OBJECT_ARRAY_TYPE = Type.getType(Object[].class);
private static final Method BOOLEAN_VALUE = Method.getMethod("boolean booleanValue()");
private static final Method CHAR_VALUE = Method.getMethod("char charValue()");
private static final Method INT_VALUE = Method.getMethod("int intValue()");
private static final Method FLOAT_VALUE = Method.getMethod("float floatValue()");
private static final Method LONG_VALUE = Method.getMethod("long longValue()");
private static final Method DOUBLE_VALUE = Method.getMethod("double doubleValue()");
public static final String DEFAULT_INNER_VARIABLE_PREFIX = "_$bytekit$_";
private final LabelNode interceptorVariableStartLabelNode = new LabelNode();
private final LabelNode interceptorVariableEndLabelNode = new LabelNode();
private AbstractInsnNode enterInsnNode;
// TODO 这里应该直接从 InsnList 里来取?因为插入代码之后,这个会改变的。
// TODO 这个没有被使用到,是不是没用的??
private AbstractInsnNode lastInsnNode;
/**
* variable
*/
private boolean keepLocalVariableNames;
private String innerVariablePrefix;
private String returnVariableName;
private String throwVariableName;
private String invokeArgsVariableName;
private String monitorVariableName;
private LocalVariableNode returnVariableNode = null;
private LocalVariableNode throwVariableNode = null;
private LocalVariableNode invokeArgsVariableNode = null;
private LocalVariableNode monitorVariableNode = null; // for synchronized
private String invokeReturnVariablePrefix;
private Map<String, LocalVariableNode> invokeReturnVariableNodeMap = new HashMap<String, LocalVariableNode>();
private TryCatchBlock tryCatchBlock = null;
private LocationFilter locationFilter = new DefaultLocationFilter();
public MethodProcessor(final ClassNode classNode, final MethodNode methodNode) {
this(classNode, methodNode, false);
}
public MethodProcessor(final ClassNode classNode, final MethodNode methodNode, LocationFilter locationFilter) {
this(classNode, methodNode, false);
this.locationFilter = locationFilter;
}
public MethodProcessor(final ClassNode classNode, final MethodNode methodNode, boolean keepLocalVariableNames) {
this(classNode.name, methodNode, keepLocalVariableNames);
this.classNode = classNode;
}
public MethodProcessor(final String owner, final MethodNode methodNode, boolean keepLocalVariableNames) {
this.owner = owner;
this.methodNode = methodNode;
this.nextLocals = methodNode.maxLocals;
this.argumentTypes = Type.getArgumentTypes(methodNode.desc);
this.returnType = Type.getReturnType(methodNode.desc);
this.keepLocalVariableNames = keepLocalVariableNames;
// find enter & exit instruction.
if (isConstructor()) {
this.enterInsnNode = findInitConstructorInstruction();
} else {
this.enterInsnNode = methodNode.instructions.getFirst();
}
// when the method is empty, both enterInsnNode and lastInsnNode are Opcodes.RETURN ;
this.lastInsnNode = methodNode.instructions.getLast();
// setup interceptor variables start/end label.
this.methodNode.instructions.insertBefore(this.enterInsnNode, this.interceptorVariableStartLabelNode);
this.methodNode.instructions.insert(this.lastInsnNode, this.interceptorVariableEndLabelNode);
initInnerVariablePrefix();
}
public MethodProcessor(final String owner, final MethodNode methodNode) {
this(owner, methodNode, false);
}
private void initInnerVariablePrefix() {
String prefix = DEFAULT_INNER_VARIABLE_PREFIX;
int count = 0;
while(existLocalVariableWithPrefix(prefix)) {
prefix = DEFAULT_INNER_VARIABLE_PREFIX + count + "_";
count++;
}
this.innerVariablePrefix = prefix;
returnVariableName = innerVariablePrefix + "_return";
throwVariableName = innerVariablePrefix + "_throw";
invokeArgsVariableName = innerVariablePrefix + "_invokeArgs";
monitorVariableName = innerVariablePrefix + "_monitor";
invokeReturnVariablePrefix = innerVariablePrefix + "_invokeReturn_";
}
private boolean existLocalVariableWithPrefix(String prefix) {
for (LocalVariableNode variableNode : this.methodNode.localVariables) {
if (variableNode.name.startsWith(prefix)) {
return true;
}
}
return false;
}
public LocalVariableNode initMonitorVariableNode() {
if (monitorVariableNode == null) {
monitorVariableNode = this.addInterceptorLocalVariable(monitorVariableName, OBJECT_TYPE.getDescriptor());
}
return monitorVariableNode;
}
public LocalVariableNode initThrowVariableNode() {
if (throwVariableNode == null) {
throwVariableNode = this.addInterceptorLocalVariable(throwVariableName, THROWABLE_TYPE.getDescriptor());
}
return throwVariableNode;
}
public LocalVariableNode initInvokeArgsVariableNode() {
if (invokeArgsVariableNode == null) {
invokeArgsVariableNode = this.addInterceptorLocalVariable(invokeArgsVariableName,
OBJECT_ARRAY_TYPE.getDescriptor());
}
return invokeArgsVariableNode;
}
public LocalVariableNode initReturnVariableNode() {
if (returnVariableNode == null) {
returnVariableNode = this.addInterceptorLocalVariable(returnVariableName, returnType.getDescriptor());
}
return returnVariableNode;
}
/**
*
* @param name
* @param type
* @return
*/
public LocalVariableNode initInvokeReturnVariableNode(String name, Type type) {
String key = this.invokeReturnVariablePrefix + name;
LocalVariableNode variableNode = invokeReturnVariableNodeMap.get(key);
if (variableNode == null) {
variableNode = this.addInterceptorLocalVariable(key, type.getDescriptor());
invokeReturnVariableNodeMap.put(key, variableNode);
}
return variableNode;
}
public TryCatchBlock initTryCatchBlock() {
return initTryCatchBlock(THROWABLE_TYPE.getInternalName());
}
public TryCatchBlock initTryCatchBlock(String exception) {
if( this.tryCatchBlock == null) {
this.tryCatchBlock = new TryCatchBlock(methodNode, exception);
this.methodNode.instructions.insertBefore(this.getEnterInsnNode(), tryCatchBlock.getStartLabelNode());
this.methodNode.instructions.insert(this.getLastInsnNode(), tryCatchBlock.getEndLabelNode());
InsnList instructions = new InsnList();
AsmOpUtils.throwException(instructions);
this.methodNode.instructions.insert(tryCatchBlock.getEndLabelNode(), instructions);
tryCatchBlock.sort();
}
return tryCatchBlock;
}
AbstractInsnNode findInitConstructorInstruction() {
int nested = 0;
for (AbstractInsnNode insnNode = this.methodNode.instructions.getFirst(); insnNode != null; insnNode = insnNode
.getNext()) {
if (insnNode instanceof TypeInsnNode) {
if (insnNode.getOpcode() == Opcodes.NEW) {
// new object().
nested++;
}
} else if (insnNode instanceof MethodInsnNode) {
final MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode;
if (methodInsnNode.getOpcode() == Opcodes.INVOKESPECIAL && methodInsnNode.name.equals("<init>")) {
if (--nested < 0) {
// find this() or super().
return insnNode.getNext();
}
}
}
}
return null;
}
public AbstractInsnNode getEnterInsnNode() {
return enterInsnNode;
}
public AbstractInsnNode getLastInsnNode() {
return lastInsnNode;
}
public String[] getParameterTypes() {
final String[] parameterTypes = new String[this.argumentTypes.length];
for (int i = 0; i < this.argumentTypes.length; i++) {
parameterTypes[i] = this.argumentTypes[i].getClassName();
}
return parameterTypes;
}
public String[] getParameterNames() {
if (this.argumentTypes.length == 0) {
return new String[0];
}
final List<LocalVariableNode> localVariableNodes = this.methodNode.localVariables;
int localVariableStartIndex = 1;
if (isStatic()) {
// static method is none this.
localVariableStartIndex = 0;
}
if (localVariableNodes == null || localVariableNodes.size() <= localVariableStartIndex
|| (this.argumentTypes.length + localVariableStartIndex) > localVariableNodes.size()) {
// make simple argument names.
final String[] names = new String[this.argumentTypes.length];
for (int i = 0; i < this.argumentTypes.length; i++) {
final String className = this.argumentTypes[i].getClassName();
if (className != null) {
final int findIndex = className.lastIndexOf('.');
if (findIndex == -1) {
names[i] = className;
} else {
names[i] = className.substring(findIndex + 1);
}
} else {
names[i] = this.argumentTypes[i].getDescriptor();
}
}
return names;
}
// sort by index.
Collections.sort(localVariableNodes, new Comparator<LocalVariableNode>() {
@Override
public int compare(LocalVariableNode o1, LocalVariableNode o2) {
return o1.index - o2.index;
}
});
String[] names = new String[this.argumentTypes.length];
for (int i = 0; i < this.argumentTypes.length; i++) {
final String name = localVariableNodes.get(localVariableStartIndex++).name;
if (name != null) {
names[i] = name;
} else {
names[i] = "";
}
}
return names;
}
public Type getReturnType() {
return this.returnType;
}
private boolean hasLocalVariable(String name) {
List<LocalVariableNode> localVariableNodes = this.methodNode.localVariables;
if (localVariableNodes == null) {
return false;
}
for (LocalVariableNode node : localVariableNodes) {
if (node.name.equals(name)) {
return true;
}
}
return false;
}
public void loadThis(final InsnList instructions) {
if (isConstructor()) {
// load this.
loadVar(instructions, 0);
} else {
if (isStatic()) {
// load null.
loadNull(instructions);
} else {
// load this.
loadVar(instructions, 0);
}
}
}
void storeVar(final InsnList instructions, final int index) {
instructions.add(new VarInsnNode(Opcodes.ASTORE, index));
}
void storeInt(final InsnList instructions, final int index) {
instructions.add(new VarInsnNode(Opcodes.ISTORE, index));
}
void loadNull(final InsnList instructions) {
instructions.add(new InsnNode(Opcodes.ACONST_NULL));
}
void loadVar(final InsnList instructions, final int index) {
instructions.add(new VarInsnNode(Opcodes.ALOAD, index));
}
void loadInt(final InsnList instructions, final int index) {
instructions.add(new VarInsnNode(Opcodes.ILOAD, index));
}
boolean isReturnCode(final int opcode) {
return opcode == Opcodes.IRETURN || opcode == Opcodes.LRETURN || opcode == Opcodes.FRETURN
|| opcode == Opcodes.DRETURN || opcode == Opcodes.ARETURN || opcode == Opcodes.RETURN;
}
Type getBoxedType(final Type type) {
switch (type.getSort()) {
case Type.BYTE:
return BYTE_TYPE;
case Type.BOOLEAN:
return BOOLEAN_TYPE;
case Type.SHORT:
return SHORT_TYPE;
case Type.CHAR:
return CHARACTER_TYPE;
case Type.INT:
return INTEGER_TYPE;
case Type.FLOAT:
return FLOAT_TYPE;
case Type.LONG:
return LONG_TYPE;
case Type.DOUBLE:
return DOUBLE_TYPE;
}
return type;
}
void push(InsnList insnList, final int value) {
if (value >= -1 && value <= 5) {
insnList.add(new InsnNode(Opcodes.ICONST_0 + value));
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
insnList.add(new IntInsnNode(Opcodes.BIPUSH, value));
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
insnList.add(new IntInsnNode(Opcodes.SIPUSH, value));
} else {
insnList.add(new LdcInsnNode(value));
}
}
void push(InsnList insnList, final String value) {
if (value == null) {
insnList.add(new InsnNode(Opcodes.ACONST_NULL));
} else {
insnList.add(new LdcInsnNode(value));
}
}
void newArray(final InsnList insnList, final Type type) {
insnList.add(new TypeInsnNode(Opcodes.ANEWARRAY, type.getInternalName()));
}
void dup(final InsnList insnList) {
insnList.add(new InsnNode(Opcodes.DUP));
}
void dup2(final InsnList insnList) {
insnList.add(new InsnNode(Opcodes.DUP2));
}
void dupX1(final InsnList insnList) {
insnList.add(new InsnNode(Opcodes.DUP_X1));
}
void dupX2(final InsnList insnList) {
insnList.add(new InsnNode(Opcodes.DUP_X2));
}
void pop(final InsnList insnList) {
insnList.add(new InsnNode(Opcodes.POP));
}
void swap(final InsnList insnList) {
insnList.add(new InsnNode(Opcodes.SWAP));
}
void loadArgsVar(final InsnList instructions) {
if (this.argumentTypes.length == 0) {
// null.
loadNull(instructions);
return;
}
push(instructions, this.argumentTypes.length);
// new array
newArray(instructions, OBJECT_TYPE);
for (int i = 0; i < this.argumentTypes.length; i++) {
Type type = this.argumentTypes[i];
dup(instructions);
push(instructions, i);
// loadArg
loadArg(instructions, this.argumentTypes, i);
// box
box(instructions, type);
// arrayStore
arrayStore(instructions, OBJECT_TYPE);
}
}
void loadArgs(final InsnList instructions) {
for (int i = 0; i < this.argumentTypes.length; i++) {
loadArg(instructions, this.argumentTypes, i);
}
}
void loadArg(final InsnList instructions, Type[] argumentTypes, int i) {
final int index = getArgIndex(argumentTypes, i);
final Type type = argumentTypes[i];
instructions.add(new VarInsnNode(type.getOpcode(Opcodes.ILOAD), index));
}
int getArgIndex(final Type[] argumentTypes, final int arg) {
int index = isStatic() ? 0 : 1;
for (int i = 0; i < arg; i++) {
index += argumentTypes[i].getSize();
}
return index;
}
void box(final InsnList instructions, Type type) {
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
return;
}
if (type == Type.VOID_TYPE) {
// push null
instructions.add(new InsnNode(Opcodes.ACONST_NULL));
} else {
Type boxed = getBoxedType(type);
// new instance.
newInstance(instructions, boxed);
if (type.getSize() == 2) {
// Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
// dupX2
dupX2(instructions);
// dupX2
dupX2(instructions);
// pop
pop(instructions);
} else {
// p -> po -> opo -> oop -> o
// dupX1
dupX1(instructions);
// swap
swap(instructions);
}
invokeConstructor(instructions, boxed, new Method("<init>", Type.VOID_TYPE, new Type[] { type }));
}
}
void unbox(final InsnList instructions, Type type) {
Type t = NUMBER_TYPE;
Method sig = null;
switch (type.getSort()) {
case Type.VOID:
return;
case Type.CHAR:
t = CHARACTER_TYPE;
sig = CHAR_VALUE;
break;
case Type.BOOLEAN:
t = BOOLEAN_TYPE;
sig = BOOLEAN_VALUE;
break;
case Type.DOUBLE:
sig = DOUBLE_VALUE;
break;
case Type.FLOAT:
sig = FLOAT_VALUE;
break;
case Type.LONG:
sig = LONG_VALUE;
break;
case Type.INT:
case Type.SHORT:
case Type.BYTE:
sig = INT_VALUE;
}
if (sig == null) {
instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, type.getInternalName()));
} else {
instructions.add(new TypeInsnNode(Opcodes.CHECKCAST, t.getInternalName()));
instructions.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, t.getInternalName(), sig.getName(),
sig.getDescriptor(), false));
}
}
void arrayStore(final InsnList instructions, final Type type) {
instructions.add(new InsnNode(type.getOpcode(Opcodes.IASTORE)));
}
void arrayLoad(final InsnList instructions, final Type type) {
instructions.add(new InsnNode(type.getOpcode(Opcodes.IALOAD)));
}
void newInstance(final InsnList instructions, final Type type) {
instructions.add(new TypeInsnNode(Opcodes.NEW, type.getInternalName()));
}
void invokeConstructor(final InsnList instructions, final Type type, final Method method) {
String owner = type.getSort() == Type.ARRAY ? type.getDescriptor() : type.getInternalName();
instructions
.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, owner, method.getName(), method.getDescriptor(), false));
}
LocalVariableNode addInterceptorLocalVariable(final String name, final String desc) {
return addLocalVariable(name, desc, this.interceptorVariableStartLabelNode,
this.interceptorVariableEndLabelNode);
}
LocalVariableNode addLocalVariable(final String name, final String desc, final LabelNode start,
final LabelNode end) {
Type type = Type.getType(desc);
int index = this.nextLocals;
this.nextLocals += type.getSize();
methodNode.maxLocals = this.nextLocals;
final LocalVariableNode node = new LocalVariableNode(name, desc, null, start, end, index);
if (keepLocalVariableNames) {
this.methodNode.localVariables.add(node);
}
return node;
}
public void returnValue(final InsnList instructions) {
instructions.add(new InsnNode(this.returnType.getOpcode(Opcodes.IRETURN)));
}
public boolean isStatic() {
return (this.methodNode.access & Opcodes.ACC_STATIC) != 0;
}
public boolean isConstructor() {
return this.methodNode.name != null && this.methodNode.name.equals("<init>");
}
public MethodNode getMethodNode() {
return methodNode;
}
public void setMethodNode(MethodNode methodNode) {
this.methodNode = methodNode;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public ClassNode getClassNode() {
return classNode;
}
public void setClassNode(ClassNode classNode) {
this.classNode = classNode;
}
public LocationFilter getLocationFilter() {
return locationFilter;
}
/**
* TODO argsstackslotinline stackslot
* @param owner
* @param tmpToInlineMethodNode
*/
public void inline(String owner, MethodNode toInlineMethodNode) {
ListIterator<AbstractInsnNode> originMethodIter = this.methodNode.instructions.iterator();
while(originMethodIter.hasNext()) {
AbstractInsnNode originMethodInsnNode = originMethodIter.next();
if (originMethodInsnNode instanceof MethodInsnNode) {
MethodInsnNode methodInsnNode = (MethodInsnNode) originMethodInsnNode;
if (methodInsnNode.owner.equals(owner) && methodInsnNode.name.equals(toInlineMethodNode.name)
&& methodInsnNode.desc.equals(toInlineMethodNode.desc)) {
// 要copy一份否则inline多次会出问题
MethodNode tmpToInlineMethodNode = AsmUtils.copy(toInlineMethodNode);
tmpToInlineMethodNode = AsmUtils.removeLineNumbers(tmpToInlineMethodNode);
LabelNode end = new LabelNode();
this.methodNode.instructions.insert(methodInsnNode, end);
InsnList instructions = new InsnList();
// 要先记录好当前的 maxLocals ,然后再依次把 栈上的 args保存起来 ,后面调整 VarInsnNode index里要加上当前的 maxLocals
// save args to local vars
int currentMaxLocals = this.nextLocals;
int off = (tmpToInlineMethodNode.access & Opcodes.ACC_STATIC) != 0 ? 0 : 1;
Type[] args = Type.getArgumentTypes(tmpToInlineMethodNode.desc);
int argsOff = off;
for(int i = 0; i < args.length; ++i) {
argsOff += args[i].getSize();
}
// 记录新的 maxLocals
this.nextLocals += argsOff;
methodNode.maxLocals = this.nextLocals;
for(int i = args.length - 1; i >= 0; --i) {
argsOff -= args[i].getSize();
// this.visitVarInsn(args[i].getOpcode(Opcodes.ISTORE), argsOff);
AsmOpUtils.storeVar(instructions, args[i], currentMaxLocals + argsOff);
}
// this
if (off > 0) {
// this.visitVarInsn(Opcodes.ASTORE, 0);
AsmOpUtils.storeVar(instructions, OBJECT_TYPE, currentMaxLocals);
}
ListIterator<AbstractInsnNode> inlineIterator = tmpToInlineMethodNode.instructions.iterator();
while(inlineIterator.hasNext()) {
AbstractInsnNode abstractInsnNode = inlineIterator.next();
if(abstractInsnNode instanceof FrameNode) {
continue;
}
//修改inline代码中的使用到局部变量的指令的var操作数(变量slot)
if(abstractInsnNode instanceof VarInsnNode) {
VarInsnNode varInsnNode = (VarInsnNode) abstractInsnNode;
varInsnNode.var += currentMaxLocals;
} else if (abstractInsnNode instanceof IincInsnNode) {
IincInsnNode iincInsnNode = (IincInsnNode) abstractInsnNode;
iincInsnNode.var += currentMaxLocals;
}
int opcode = abstractInsnNode.getOpcode();
if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) {
// super.visitJumpInsn(Opcodes.GOTO, end);
// instructions.add(new JumpInsnNode(Opcodes.GOTO, end));
inlineIterator.remove();
instructions.add(new JumpInsnNode(Opcodes.GOTO, end));
continue;
}
inlineIterator.remove();
instructions.add(abstractInsnNode);
}
// 插入inline之后的代码再删除掉原来的 MethodInsnNode
this.methodNode.instructions.insertBefore(methodInsnNode, instructions);
originMethodIter.remove();
// try catch 块加上,然后排序
if(this.methodNode.tryCatchBlocks != null && tmpToInlineMethodNode.tryCatchBlocks != null) {
this.methodNode.tryCatchBlocks.addAll(tmpToInlineMethodNode.tryCatchBlocks);
}
this.sortTryCatchBlock();
}
}
}
}
public void sortTryCatchBlock() {
if (this.methodNode.tryCatchBlocks == null) {
return;
}
// Compares TryCatchBlockNodes by the length of their "try" block.
Collections.sort(this.methodNode.tryCatchBlocks, new Comparator<TryCatchBlockNode>() {
@Override
public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
int len1 = blockLength(t1);
int len2 = blockLength(t2);
return len1 - len2;
}
private int blockLength(TryCatchBlockNode block) {
final int startidx = methodNode.instructions.indexOf(block.start);
final int endidx = methodNode.instructions.indexOf(block.end);
return endidx - startidx;
}
});
// Updates the 'target' of each try catch block annotation.
for (int i = 0; i < this.methodNode.tryCatchBlocks.size(); i++) {
this.methodNode.tryCatchBlocks.get(i).updateIndex(i);
}
}
}

@ -1,64 +0,0 @@
package com.taobao.arthas.bytekit.asm;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LabelNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.TryCatchBlockNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class MyTryCatchBlock {
private final MethodNode methodNode;
private final LabelNode startLabelNode = new LabelNode();
private final LabelNode endLabelNode = new LabelNode();
private final LabelNode handlerLabelNode = new LabelNode();
public MyTryCatchBlock(final MethodNode methodNode) {
this.methodNode = methodNode;
final TryCatchBlockNode tryCatchBlockNode = new TryCatchBlockNode(this.startLabelNode, this.endLabelNode, this.handlerLabelNode, "java/lang/Throwable");
if (this.methodNode.tryCatchBlocks == null) {
this.methodNode.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
}
this.methodNode.tryCatchBlocks.add(tryCatchBlockNode);
}
public LabelNode getStartLabelNode() {
return this.startLabelNode;
}
public LabelNode getEndLabelNode() {
return this.endLabelNode;
}
public LabelNode getHandlerLabelNode() {
return this.handlerLabelNode;
}
public void sort() {
if (this.methodNode.tryCatchBlocks == null) {
return;
}
// Compares TryCatchBlockNodes by the length of their "try" block.
Collections.sort(this.methodNode.tryCatchBlocks, new Comparator<TryCatchBlockNode>() {
@Override
public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
int len1 = blockLength(t1);
int len2 = blockLength(t2);
return len1 - len2;
}
private int blockLength(TryCatchBlockNode block) {
final int startidx = methodNode.instructions.indexOf(block.start);
final int endidx = methodNode.instructions.indexOf(block.end);
return endidx - startidx;
}
});
// Updates the 'target' of each try catch block annotation.
for (int i = 0; i < this.methodNode.tryCatchBlocks.size(); i++) {
this.methodNode.tryCatchBlocks.get(i).updateIndex(i);
}
}
}

@ -1,66 +0,0 @@
package com.taobao.arthas.bytekit.asm;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LabelNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.TryCatchBlockNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class TryCatchBlock {
private final MethodNode methodNode;
private final LabelNode startLabelNode = new LabelNode();
private final LabelNode endLabelNode = new LabelNode();
public TryCatchBlock(final MethodNode methodNode) {
this(methodNode, Type.getType(Throwable.class).getInternalName());
}
public TryCatchBlock(final MethodNode methodNode, String exception) {
this.methodNode = methodNode;
final TryCatchBlockNode tryCatchBlockNode = new TryCatchBlockNode(this.startLabelNode, this.endLabelNode,
this.endLabelNode, exception);
if (this.methodNode.tryCatchBlocks == null) {
this.methodNode.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
}
this.methodNode.tryCatchBlocks.add(tryCatchBlockNode);
}
public LabelNode getStartLabelNode() {
return this.startLabelNode;
}
public LabelNode getEndLabelNode() {
return this.endLabelNode;
}
public void sort() {
if (this.methodNode.tryCatchBlocks == null) {
return;
}
// Compares TryCatchBlockNodes by the length of their "try" block.
Collections.sort(this.methodNode.tryCatchBlocks, new Comparator<TryCatchBlockNode>() {
@Override
public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
int len1 = blockLength(t1);
int len2 = blockLength(t2);
return len1 - len2;
}
private int blockLength(TryCatchBlockNode block) {
final int startidx = methodNode.instructions.indexOf(block.start);
final int endidx = methodNode.instructions.indexOf(block.end);
return endidx - startidx;
}
});
// Updates the 'target' of each try catch block annotation.
for (int i = 0; i < this.methodNode.tryCatchBlocks.size(); i++) {
this.methodNode.tryCatchBlocks.get(i).updateIndex(i);
}
}
}

@ -1,431 +0,0 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2008-10 Red Hat and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
* @authors Andrew Dinn
*/
package com.taobao.arthas.bytekit.asm;
/**
* Helpoer class providing static methods for manipulating type and class names,
* field and method descriptor names etc
*/
public class TypeHelper {
public static boolean equalDescriptors(String desc1, String desc2)
{
int idx1 = 0, idx2 = 0;
int len1 = desc1.length(), len2 = desc2.length();
while (idx1 < len1) {
// check the other has not dropped off the end
if (idx2 == len2) {
if ((idx1 == (len1 - 1)) && (desc1.charAt(idx1) == '$')) {
return true;
}
return false;
}
// check type is the same
char char1 = desc1.charAt(idx1);
char char2 = desc2.charAt(idx2);
// if we have a $ at the end of the descriptor then this means any return
// type so special case this
if ((char1 == '$' && idx1 == len1 - 1) || (char2 == '$' && idx2 == len2 - 1)) {
return true;
}
// otherwise the chars must match
if (char1 != char2) {
return false;
}
// however an L indicates a class name and we allow a classname without a package
// to match a class name with a package
if (char1 == 'L') {
// ok, ensure the names must match modulo a missing package
int end1 = idx1 + 1;
int end2 = idx2 + 1;
while (end1 < len1 && desc1.charAt(end1) != ';') {
end1++;
}
while (end2 < len2 && desc2.charAt(end2) != ';') {
end2++;
}
if (end1 == len1 || end2 == len2) {
// bad format for desc!!
return false;
}
String typeName1 = desc1.substring(idx1 + 1, end1);
String typeName2 = desc2.substring(idx2 + 1, end2);
if (!typeName1.equals(typeName2)) {
int tailIdx1 = typeName1.lastIndexOf('/');
int tailIdx2 = typeName2.lastIndexOf('/');
if (tailIdx1 > 0) {
if (tailIdx2 > 0) {
// both specify packages so they must be different types
return false;
} else {
// only type 1 specifies a package so type 2 should match the tail
if (!typeName2.equals(typeName1.substring(tailIdx1 + 1))) {
return false;
}
}
} else {
if (tailIdx2 > 0) {
// only type 2 specifies a package so type 1 should match the tail
if (!typeName1.equals(typeName2.substring(tailIdx2 + 1))) {
return false;
}
} else {
// neither specify packages so they must be different types
return false;
}
}
}
// skp past ';'s
idx1 = end1;
idx2 = end2;
}
idx1++;
idx2++;
}
// check the other has not reached the end
if (idx2 != len2) {
return false;
}
return true;
}
/**
* convert a classname from canonical form to the form used to represent it externally i.e. replace
* all dots with slashes
*
* @param className the canonical name
* @return the external name
*/
public static String externalizeClass(String className)
{
return className.replace('.', '/');
}
/**
* convert a classname from external form to canonical form i.e. replace
* all slashes with dots
*
* @param className the external name
* @return the canonical name
*/
public static String internalizeClass(String className)
{
String result = className;
int length = result.length();
if (result.charAt(length - 1) == ';') {
result = result.substring(1, length - 2);
}
result = result.replace('/', '.');
return result;
}
/**
* convert a type name from canonical form to the form used to represent it externally i.e.
* replace primitive type names by the appropriate single letter types, class names
* by the externalized class name bracketed by 'L' and ';' and array names by the
* base type name preceded by '['.
*
* @param typeName the type name
* @return the external name
*/
public static String externalizeType(String typeName)
{
String externalName = "";
String[] typeAndArrayIndices = typeName.split("\\[");
String baseType = typeAndArrayIndices[0].trim();
for (int i = 1; i< typeAndArrayIndices.length; i++) {
String arrayIdx = typeAndArrayIndices[i];
if (arrayIdx.indexOf("\\]") != 0) {
externalName += '[';
}
}
for (int i = 0; i < internalNames.length; i++) {
if (internalNames[i].equals(baseType)) {
externalName += externalNames[i];
return externalName;
}
}
externalName += "L" + externalizeClass(baseType) + ";";
return externalName;
}
/**
* list of well known typenames as written in Java code
*/
final static private String[] internalNames = {
"", /* equivalent to void */
"void",
"byte",
"char",
"short",
"int",
"long",
"float",
"double",
"boolean",
"Byte",
"Character",
"Short",
"Integer",
"Long",
"Float",
"Double",
"String",
"java.lang.Byte",
"java.lang.Character",
"java.lang.Short",
"java.lang.Integer",
"java.lang.Long",
"java.lang.Float",
"java.lang.Double",
"java.lang.String"
};
/**
* list of typenames in external form corresponding to entries ni previous list
*/
final static private String[] externalNames = {
"$",
"V",
"B",
"C",
"S",
"I",
"J",
"F",
"D",
"Z",
"Ljava/lang/Byte;",
"Ljava/lang/Character;",
"Ljava/lang/Short;",
"Ljava/lang/Integer;",
"Ljava/lang/Long;",
"Ljava/lang/Float;",
"Ljava/lang/Double;",
"Ljava/lang/String;",
"Ljava/lang/Byte;",
"Ljava/lang/Character;",
"Ljava/lang/Short;",
"Ljava/lang/Integer;",
"Ljava/lang/Long;",
"Ljava/lang/Float;",
"Ljava/lang/Double;",
"Ljava/lang/String;"
};
/**
* convert a method descriptor from canonical form to the form used to represent it externally
*
* @param desc the method descriptor which must be trimmed of any surrounding white space
* @return an externalised form for the descriptor
*/
public static String externalizeDescriptor(String desc)
{
// the descriptor will start with '(' and the arguments list should end with ')' and,
// if it is not void be followed by a return type
int openIdx = desc.indexOf('(');
int closeIdx = desc.indexOf(')');
int length = desc.length();
if (openIdx != 0) {
return "";
}
if (closeIdx < 0) {
return "";
}
String retType = (closeIdx < length ? desc.substring(closeIdx + 1).trim() : "");
String externalRetType = externalizeType(retType);
String argString = desc.substring(1, closeIdx).trim();
String externalArgs = "";
if (argString.equals("")) {
externalArgs = argString;
} else {
String[] args = desc.substring(1, closeIdx).trim().split(",");
for (int i = 0; i < args.length ; i++) {
externalArgs += externalizeType(args[i]);
}
}
return "(" + externalArgs + ")" + externalRetType;
}
/**
* convert a method descriptor from the form used to represent it externally to canonical form
*
* @param desc the method descriptor which must be trimmed of any surrounding white space and start with "(".
* it must end either with ")" or with ") " followed by an exernalized return type
* @return an internalised form for the descriptor, possibly followed by a space and externalized return type
*/
public static String internalizeDescriptor(String desc)
{
StringBuffer buffer = new StringBuffer();
String sepr = "";
int argStart = desc.indexOf('(');
int argEnd = desc.indexOf(')');
int max = desc.length();
if (argStart < 0 || argEnd < 0) {
return "(...)";
}
int arrayCount = 0;
boolean addSepr = false;
buffer.append("(");
for (int idx = argStart + 1; idx < max;) {
char next = desc.charAt(idx);
if (addSepr) {
while (arrayCount > 0) {
buffer.append("[]");
arrayCount--;
}
buffer.append(sepr);
}
addSepr = true;
switch(next) {
case 'B':
{
buffer.append("byte");
}
break;
case 'C':
{
buffer.append("char");
}
break;
case 'S':
{
buffer.append("short");
}
break;
case 'I':
{
buffer.append("int");
}
break;
case 'J':
{
buffer.append("long");
}
break;
case 'Z':
{
buffer.append("boolean");
}
break;
case 'F':
{
buffer.append("float");
}
break;
case 'D':
{
buffer.append("double");
}
case 'V':
{
buffer.append("void");
}
break;
case 'L':
{
int tailIdx = idx+1;
while (tailIdx < max) {
char tailChar = desc.charAt(tailIdx);
if (tailChar == ';') {
break;
}
if (tailChar == '/')
{
tailChar = '.';
}
buffer.append(tailChar);
tailIdx++;
}
idx = tailIdx;
}
break;
case '[':
{
arrayCount++;
addSepr = false;
}
break;
case ')':
{
if (idx == argEnd - 1) {
buffer.append(")");
} else {
// leave room for return type
buffer.append(") ");
}
addSepr = false;
}
break;
default:
{
addSepr = false;
}
}
idx++;
if (idx < argEnd) {
sepr = ",";
} else {
sepr = "";
}
}
return buffer.toString();
}
/**
* split off the method name preceding the signature and return it
* @param targetMethod - the unqualified method name, possibly including signature
* @return the method name
*/
public static String parseMethodName(String targetMethod) {
int sigIdx = targetMethod.indexOf("(");
if (sigIdx > 0) {
return targetMethod.substring(0, sigIdx).trim();
} else {
return targetMethod;
}
}
/**
* split off the signature following the method name and return it
* @param targetMethod - the unqualified method name, possibly including signature
* @return the signature
*/
public static String parseMethodDescriptor(String targetMethod) {
int descIdx = targetMethod.indexOf("(");
if (descIdx >= 0) {
String desc = targetMethod.substring(descIdx, targetMethod.length()).trim();
return externalizeDescriptor(desc);
} else {
return "";
}
}
}

@ -1,33 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
public class ArgNamesBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
String[] parameterNames = bindingContext.getMethodProcessor().getParameterNames();
AsmOpUtils.push(instructions, parameterNames.length);
AsmOpUtils.newArray(instructions, AsmOpUtils.STRING_TYPE);
for(int i = 0; i < parameterNames.length; ++i) {
AsmOpUtils.dup(instructions);
AsmOpUtils.push(instructions, i);
AsmOpUtils.push(instructions, parameterNames[i]);
AsmOpUtils.arrayStore(instructions, AsmOpUtils.STRING_TYPE);
}
}
@Override
public Type getType(BindingContext bindingContext) {
return AsmOpUtils.STRING_ARRAY_TYPE;
}
}

@ -1,20 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
public class ArgsBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
AsmOpUtils.loadArgArray(instructions, bindingContext.getMethodProcessor().getMethodNode());
}
@Override
public Type getType(BindingContext bindingContext) {
return AsmOpUtils.OBJECT_ARRAY_TYPE;
}
}

@ -1,50 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
* TODO stack binding optional ArrayBinding
* @author hengyunabc
*
*/
public class ArrayBinding extends Binding{
// TODO 数组的 type是什么
// private Type type;
List<Binding> bindingList = new ArrayList<Binding>();
public ArrayBinding(List<Binding> bindingList) {
this.bindingList = bindingList;
}
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
AsmOpUtils.push(instructions, bindingList.size());
AsmOpUtils.newArray(instructions, AsmOpUtils.OBJECT_TYPE);
for(int i = 0; i < bindingList.size(); ++i) {
AsmOpUtils.dup(instructions);
AsmOpUtils.push(instructions, i);
Binding binding = bindingList.get(i);
binding.pushOntoStack(instructions, bindingContext);
AsmOpUtils.box(instructions, binding.getType(bindingContext));
AsmOpUtils.arrayStore(instructions, AsmOpUtils.OBJECT_TYPE);
}
}
@Override
public Type getType(BindingContext bindingContext) {
// TODO Auto-generated method stub
return null;
}
}

@ -1,424 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.taobao.arthas.bytekit.asm.binding.annotation.BindingParser;
import com.taobao.arthas.bytekit.asm.binding.annotation.BindingParserHandler;
public abstract class Binding {
/**
* nulljava.util.Optional
* @return
*/
public boolean optional() {
return false;
}
/**
* bindingfieldfield
* @return
*/
public boolean check(BindingContext bindingContext) {
return true;
}
/**
* binding
* @param instructions
* @param bindingContext
*/
public abstract void pushOntoStack(InsnList instructions, BindingContext bindingContext);
public abstract Type getType( BindingContext bindingContext);
public boolean fromStack() {
return false;
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = ArgsBindingParser.class)
public static @interface Args {
boolean optional() default false;
}
public static class ArgsBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new ArgsBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = ArgNamesBindingParser.class)
public static @interface ArgNames {
boolean optional() default false;
}
public static class ArgNamesBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new ArgNamesBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = LocalVarsBindingParser.class)
public static @interface LocalVars {
boolean optional() default false;
}
public static class LocalVarsBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new LocalVarsBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = LocalVarNamesBindingParser.class)
public static @interface LocalVarNames {
boolean optional() default false;
}
public static class LocalVarNamesBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new LocalVarNamesBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = ClassBindingParser.class)
public static @interface Class {
boolean optional() default false;
}
public static class ClassBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new ClassBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = FieldBindingParser.class)
public static @interface Field {
boolean optional() default false;
java.lang.Class<?> owner() default Void.class;
java.lang.Class<?> type() default Void.class;
String name();
boolean isStatic() default false;
boolean box() default false;
}
public static class FieldBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
Field field = (Field) annotation;
Type ownerType = Type.getType(field.owner());
if(field.owner().equals(Void.class)) {
ownerType = null;
}
Type fieldType = Type.getType(field.type());
if(field.type().equals(Void.class)) {
fieldType = null;
}
return new FieldBinding(ownerType, field.name(), fieldType,
field.isStatic(), field.box());
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = InvokeArgsBindingParser.class)
public static @interface InvokeArgs {
boolean optional() default false;
}
public static class InvokeArgsBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new InvokeArgsBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = InvokeReturnBindingParser.class)
public static @interface InvokeReturn {
boolean optional() default false;
}
public static class InvokeReturnBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new InvokeReturnBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = InvokeMethodNameBindingParser.class)
public static @interface InvokeMethodName {
boolean optional() default false;
}
public static class InvokeMethodNameBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new InvokeMethodNameBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = InvokeMethodOwnerBindingParser.class)
public static @interface InvokeMethodOwner {
boolean optional() default false;
}
public static class InvokeMethodOwnerBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new InvokeMethodOwnerBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = InvokeMethodDeclarationBindingParser.class)
public static @interface InvokeMethodDeclaration {
boolean optional() default false;
}
public static class InvokeMethodDeclarationBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new InvokeMethodDeclarationBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = InvokeInfoBindingParser.class)
public static @interface InvokeInfo {
boolean optional() default false;
}
public static class InvokeInfoBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new InvokeInfoBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = MethodBindingParser.class)
public static @interface Method {
boolean optional() default false;
}
public static class MethodBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new MethodBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = MethodNameBindingParser.class)
public static @interface MethodName {
boolean optional() default false;
}
public static class MethodNameBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new MethodNameBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = MethodDescBindingParser.class)
public static @interface MethodDesc {
boolean optional() default false;
}
public static class MethodDescBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new MethodDeclarationBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = MethodInfoBindingParser.class)
public static @interface MethodInfo {
boolean optional() default false;
}
public static class MethodInfoBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new MethodInfoBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = ReturnBindingParser.class)
public static @interface Return {
boolean optional() default false;
}
public static class ReturnBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new ReturnBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = ThisBindingParser.class)
public static @interface This {
}
public static class ThisBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new ThisBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = ThrowableBindingParser.class)
public static @interface Throwable {
boolean optional() default false;
}
public static class ThrowableBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new ThrowableBinding();
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = LineBindingParser.class)
public static @interface Line {
boolean optional() default false;
/**
* LineNumberNode true LineNumberNode
*
* @return
*/
boolean exact() default false;
}
public static class LineBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
Line line = (Line) annotation;
return new LineBinding(line.exact());
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.PARAMETER)
@BindingParserHandler(parser = MonitorBindingParser.class)
public static @interface Monitor {
boolean optional() default false;
}
public static class MonitorBindingParser implements BindingParser {
@Override
public Binding parse(Annotation annotation) {
return new MonitorBinding();
}
}
}

@ -1,41 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.taobao.arthas.bytekit.asm.MethodProcessor;
import com.taobao.arthas.bytekit.asm.location.Location;
public class BindingContext {
private MethodProcessor methodProcessor;
private Location location;
private StackSaver stackSaver;
public BindingContext(Location location, MethodProcessor methodProcessor, StackSaver stackSaver) {
this.location = location;
this.methodProcessor = methodProcessor;
this.stackSaver = stackSaver;
}
public MethodProcessor getMethodProcessor() {
return methodProcessor;
}
public void setMethodProcessor(MethodProcessor methodProcessor) {
this.methodProcessor = methodProcessor;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public StackSaver getStackSaver() {
return stackSaver;
}
public void setStackSaver(StackSaver stackSaver) {
this.stackSaver = stackSaver;
}
}

@ -1,21 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
public class ClassBinding extends Binding{
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
String owner = bindingContext.getMethodProcessor().getOwner();
AsmOpUtils.ldc(instructions, Type.getObjectType(owner));
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(Class.class);
}
}

@ -1,95 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Opcodes;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.ClassNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.FieldNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.taobao.arthas.bytekit.asm.MethodProcessor;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
import com.taobao.arthas.bytekit.utils.AsmUtils;
public class FieldBinding extends Binding {
/**
* maybe null
*/
private Type owner;
private boolean box = false;
private String name;
private boolean isStatic = false;
/**
* maybe null
*/
private Type type;
public FieldBinding(Type owner, String name, Type type, boolean isStatic, boolean box) {
this.owner = owner;
this.name = name;
this.isStatic = isStatic;
this.box = box;
this.type = type;
}
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
Type onwerType = owner;
Type fieldType = type;
boolean fieldIsStatic = isStatic;
if (owner == null) {
onwerType = Type.getObjectType(bindingContext.getMethodProcessor().getOwner());
}
// 当type是null里需要从ClassNode里查找到files确定type
MethodProcessor methodProcessor = bindingContext.getMethodProcessor();
if (fieldType == null) {
ClassNode classNode = methodProcessor.getClassNode();
if (classNode == null) {
throw new IllegalArgumentException(
"classNode is null, cann not get owner type. FieldBinding name:" + name);
}
FieldNode field = AsmUtils.findField(classNode.fields, name);
if (field == null) {
throw new IllegalArgumentException("can not find field in ClassNode. FieldBinding name:" + name);
}
fieldType = Type.getType(field.desc);
if ((field.access & Opcodes.ACC_STATIC) != 0) {
fieldIsStatic = true;
}else {
fieldIsStatic = false;
}
}
if (fieldIsStatic) {
AsmOpUtils.getStatic(instructions, onwerType, name, fieldType);
} else {
methodProcessor.loadThis(instructions);
AsmOpUtils.getField(instructions, onwerType, name, fieldType);
}
if (box) {
AsmOpUtils.box(instructions, fieldType);
}
}
@Override
public Type getType(BindingContext bindingContext) {
Type fieldType = type;
if (fieldType == null) {
ClassNode classNode = bindingContext.getMethodProcessor().getClassNode();
if (classNode == null) {
throw new IllegalArgumentException(
"classNode is null, cann not get owner type. FieldBinding name:" + name);
}
FieldNode field = AsmUtils.findField(classNode.fields, name);
if (field == null) {
throw new IllegalArgumentException("can not find field in ClassNode. FieldBinding name:" + name);
}
fieldType = Type.getType(field.desc);
}
return fieldType;
}
}

@ -1,36 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
public class IntBinding extends Binding {
private int value;
private boolean box = true;
public IntBinding(int value) {
this(value, true);
}
public IntBinding(int value, boolean box) {
this.value = value;
this.box = box;
}
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
AsmOpUtils.push(instructions, value);
if (box) {
AsmOpUtils.box(instructions, Type.INT_TYPE);
}
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.INT_TYPE;
}
}

@ -1,47 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LocalVariableNode;
import com.taobao.arthas.bytekit.asm.location.Location;
import com.taobao.arthas.bytekit.asm.location.Location.InvokeLocation;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
* invoke invoke
*
* TODO static null static
*
* @author hengyunabc
*
*/
public class InvokeArgsBinding extends Binding {
@Override
public boolean fromStack() {
return true;
}
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
Location location = bindingContext.getLocation();
if(location instanceof InvokeLocation) {
InvokeLocation invokeLocation = (InvokeLocation) location;
if(invokeLocation.isWhenComplete()) {
throw new IllegalArgumentException("InvokeArgsBinding can not work on InvokeLocation whenComplete is true.");
}
}else {
throw new IllegalArgumentException("current location is not invoke location. location: " + location);
}
LocalVariableNode invokeArgsVariableNode = bindingContext.getMethodProcessor().initInvokeArgsVariableNode();
AsmOpUtils.loadVar(instructions, AsmOpUtils.OBJECT_ARRAY_TYPE, invokeArgsVariableNode.index);
}
@Override
public Type getType(BindingContext bindingContext) {
return AsmOpUtils.OBJECT_ARRAY_TYPE;
}
}

@ -1,64 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.AbstractInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LineNumberNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodInsnNode;
import com.taobao.arthas.bytekit.asm.location.MethodInsnNodeWare;
import com.taobao.arthas.bytekit.asm.location.Location;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
* owner/method name/ method desc/ line number
*
* @author hengyunabc 2020-05-14
*
*/
public class InvokeInfoBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
Location location = bindingContext.getLocation();
if (location instanceof MethodInsnNodeWare) {
MethodInsnNodeWare methodInsnNodeWare = (MethodInsnNodeWare) location;
MethodInsnNode methodInsnNode = methodInsnNodeWare.methodInsnNode();
int line = -1;
if (location.isWhenComplete() == false) {
AbstractInsnNode insnNode = methodInsnNode.getPrevious();
while (insnNode != null) {
if (insnNode instanceof LineNumberNode) {
line = ((LineNumberNode) insnNode).line;
break;
}
insnNode = insnNode.getPrevious();
}
} else {
AbstractInsnNode insnNode = methodInsnNode.getNext();
while (insnNode != null) {
if (insnNode instanceof LineNumberNode) {
line = ((LineNumberNode) insnNode).line;
break;
}
insnNode = insnNode.getNext();
}
}
String result = methodInsnNode.owner + "|" + methodInsnNode.name + "|" + methodInsnNode.desc + "|" + line;
AsmOpUtils.push(instructions, result);
} else {
throw new IllegalArgumentException(
"InvokeMethodNameBinding location is not Invocation location, location: " + location);
}
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(String.class);
}
}

@ -1,37 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodInsnNode;
import com.taobao.arthas.bytekit.asm.location.MethodInsnNodeWare;
import com.taobao.arthas.bytekit.asm.location.Location;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
*
* @author hengyunabc
*
*/
public class InvokeMethodDeclarationBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
Location location = bindingContext.getLocation();
if (location instanceof MethodInsnNodeWare) {
MethodInsnNodeWare methodInsnNodeWare = (MethodInsnNodeWare) location;
MethodInsnNode methodInsnNode = methodInsnNodeWare.methodInsnNode();
AsmOpUtils.push(instructions, methodInsnNode.desc);
} else {
throw new IllegalArgumentException(
"InvokeMethodDeclarationBinding location is not Invocation location, location: " + location);
}
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(String.class);
}
}

@ -1,37 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodInsnNode;
import com.taobao.arthas.bytekit.asm.location.MethodInsnNodeWare;
import com.taobao.arthas.bytekit.asm.location.Location;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
*
* @author hengyunabc
*
*/
public class InvokeMethodNameBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
Location location = bindingContext.getLocation();
if (location instanceof MethodInsnNodeWare) {
MethodInsnNodeWare methodInsnNodeWare = (MethodInsnNodeWare) location;
MethodInsnNode methodInsnNode = methodInsnNodeWare.methodInsnNode();
AsmOpUtils.push(instructions, methodInsnNode.name);
} else {
throw new IllegalArgumentException(
"InvokeMethodNameBinding location is not Invocation location, location: " + location);
}
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(String.class);
}
}

@ -1,37 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodInsnNode;
import com.taobao.arthas.bytekit.asm.location.MethodInsnNodeWare;
import com.taobao.arthas.bytekit.asm.location.Location;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
*
* @author hengyunabc 2020-05-02
*
*/
public class InvokeMethodOwnerBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
Location location = bindingContext.getLocation();
if (location instanceof MethodInsnNodeWare) {
MethodInsnNodeWare methodInsnNodeWare = (MethodInsnNodeWare) location;
MethodInsnNode methodInsnNode = methodInsnNodeWare.methodInsnNode();
AsmOpUtils.push(instructions, methodInsnNode.owner);
} else {
throw new IllegalArgumentException(
"InvokeMethodOwnerBinding location is not Invocation location, location: " + location);
}
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(String.class);
}
}

@ -1,62 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.AbstractInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LocalVariableNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodInsnNode;
import com.taobao.arthas.bytekit.asm.MethodProcessor;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
import com.taobao.arthas.bytekit.utils.AsmUtils;
/**
* invoke
* @author hengyunabc
*
*/
public class InvokeReturnBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
AbstractInsnNode insnNode = bindingContext.getLocation().getInsnNode();
MethodProcessor methodProcessor = bindingContext.getMethodProcessor();
if (insnNode instanceof MethodInsnNode) {
MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode;
String uniqueNameForMethod = AsmUtils.uniqueNameForMethod(methodInsnNode.owner, methodInsnNode.name,
methodInsnNode.desc);
Type invokeReturnType = Type.getMethodType(methodInsnNode.desc).getReturnType();
if(invokeReturnType.equals(Type.VOID_TYPE)) {
AsmOpUtils.push(instructions, null);
}else {
LocalVariableNode invokeReturnVariableNode = methodProcessor.initInvokeReturnVariableNode(
uniqueNameForMethod, Type.getMethodType(methodInsnNode.desc).getReturnType());
AsmOpUtils.loadVar(instructions, invokeReturnType, invokeReturnVariableNode.index);
}
} else {
throw new IllegalArgumentException(
"InvokeReturnBinding location is not MethodInsnNode, insnNode: " + insnNode);
}
}
@Override
public boolean fromStack() {
return true;
}
@Override
public Type getType(BindingContext bindingContext) {
AbstractInsnNode insnNode = bindingContext.getLocation().getInsnNode();
if (insnNode instanceof MethodInsnNode) {
MethodInsnNode methodInsnNode = (MethodInsnNode) insnNode;
Type invokeReturnType = Type.getMethodType(methodInsnNode.desc).getReturnType();
return invokeReturnType;
} else {
throw new IllegalArgumentException(
"InvokeReturnBinding location is not MethodInsnNode, insnNode: " + insnNode);
}
}
}

@ -1,63 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.AbstractInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LineNumberNode;
import com.taobao.arthas.bytekit.asm.location.Location;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
*
* @author hengyunabc
*
*/
public class LineBinding extends Binding {
private boolean exact;
public LineBinding(boolean exact) {
this.exact = exact;
}
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
Location location = bindingContext.getLocation();
AbstractInsnNode insnNode = location.getInsnNode();
int line = -1;
if (exact) {
if (insnNode instanceof LineNumberNode) {
line = ((LineNumberNode) insnNode).line;
} else {
throw new IllegalArgumentException("LineBinding location is not LineNumberNode, insnNode: " + insnNode);
}
} else {
if (location.isWhenComplete() == false) {
while (insnNode != null) {
if (insnNode instanceof LineNumberNode) {
line = ((LineNumberNode) insnNode).line;
break;
}
insnNode = insnNode.getPrevious();
}
} else {
while (insnNode != null) {
if (insnNode instanceof LineNumberNode) {
line = ((LineNumberNode) insnNode).line;
break;
}
insnNode = insnNode.getNext();
}
}
}
AsmOpUtils.push(instructions, line);
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(int.class);
}
}

@ -1,38 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import java.util.List;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.AbstractInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LocalVariableNode;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
public class LocalVarNamesBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
AbstractInsnNode currentInsnNode = bindingContext.getLocation().getInsnNode();
List<LocalVariableNode> results = AsmOpUtils
.validVariables(bindingContext.getMethodProcessor().getMethodNode().localVariables, currentInsnNode);
AsmOpUtils.push(instructions, results.size());
AsmOpUtils.newArray(instructions, AsmOpUtils.STRING_TYPE);
for (int i = 0; i < results.size(); ++i) {
AsmOpUtils.dup(instructions);
AsmOpUtils.push(instructions, i);
AsmOpUtils.push(instructions, results.get(i).name);
AsmOpUtils.arrayStore(instructions, AsmOpUtils.STRING_TYPE);
}
}
@Override
public Type getType(BindingContext bindingContext) {
return AsmOpUtils.STRING_ARRAY_TYPE;
}
}

@ -1,49 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import java.util.List;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.AbstractInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LocalVariableNode;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
* TODO method args
* @author hengyunabc
*
*/
public class LocalVarsBinding extends Binding{
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
AbstractInsnNode currentInsnNode = bindingContext.getLocation().getInsnNode();
List<LocalVariableNode> results = AsmOpUtils
.validVariables(bindingContext.getMethodProcessor().getMethodNode().localVariables, currentInsnNode);
AsmOpUtils.push(instructions, results.size());
AsmOpUtils.newArray(instructions, AsmOpUtils.OBJECT_TYPE);
for (int i = 0; i < results.size(); ++i) {
AsmOpUtils.dup(instructions);
AsmOpUtils.push(instructions, i);
LocalVariableNode variableNode = results.get(i);
AsmOpUtils.loadVar(instructions, Type.getType(variableNode.desc), variableNode.index);
AsmOpUtils.box(instructions, Type.getType(variableNode.desc));
AsmOpUtils.arrayStore(instructions, AsmOpUtils.OBJECT_TYPE);
}
}
@Override
public Type getType(BindingContext bindingContext) {
return AsmOpUtils.OBJECT_ARRAY_TYPE;
}
}

@ -1,52 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Opcodes;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodInsnNode;
import com.taobao.arthas.bytekit.asm.MethodProcessor;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
* @author hengyunabc
*
*/
public class MethodBinding extends Binding{
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
// 先获取类本身的 class ,再调用 getDeclaredMethod ,它需要一个变长参数,实际上要传一个数组
/**
* @see java.lang.Class.getDeclaredMethod(String, Class<?>...)
*/
MethodProcessor methodProcessor = bindingContext.getMethodProcessor();
AsmOpUtils.ldc(instructions, Type.getObjectType(methodProcessor.getOwner()));
AsmOpUtils.push(instructions, methodProcessor.getMethodNode().name);
Type[] argumentTypes = Type.getMethodType(methodProcessor.getMethodNode().desc).getArgumentTypes();
AsmOpUtils.push(instructions, argumentTypes.length);
AsmOpUtils.newArray(instructions, Type.getType(Class.class));
for(int i = 0; i < argumentTypes.length; ++i) {
AsmOpUtils.dup(instructions);
AsmOpUtils.push(instructions, i);
AsmOpUtils.ldc(instructions, argumentTypes[i]);
AsmOpUtils.arrayStore(instructions, Type.getType(Class.class));
}
MethodInsnNode declaredMethodInsnNode = new MethodInsnNode(Opcodes.INVOKEVIRTUAL, Type.getType(Class.class).getInternalName(),
"getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
instructions.add(declaredMethodInsnNode);
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(java.lang.reflect.Method.class);
}
}

@ -1,30 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.taobao.arthas.bytekit.asm.MethodProcessor;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
* TODO method stringdescdescs method public
* /static throws classname | methoname | desc String
*
* @author hengyunabc
*
*/
public class MethodDeclarationBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
MethodProcessor methodProcessor = bindingContext.getMethodProcessor();
// AsmOpUtils.ldc(instructions, AsmUtils.methodDeclaration(Type.getObjectType(methodProcessor.getOwner()),
// methodProcessor.getMethodNode()));
AsmOpUtils.ldc(instructions, methodProcessor.getMethodNode().desc);
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(String.class);
}
}

@ -1,30 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodNode;
import com.taobao.arthas.bytekit.asm.MethodProcessor;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
* method name | method desc
*
* TODO line number ?
*
* @author hengyunabc 2020-05-16
*
*/
public class MethodInfoBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
MethodProcessor methodProcessor = bindingContext.getMethodProcessor();
MethodNode methodNode = methodProcessor.getMethodNode();
AsmOpUtils.ldc(instructions, methodNode.name + '|' + methodNode.desc);
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(String.class);
}
}

@ -1,25 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.taobao.arthas.bytekit.asm.MethodProcessor;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
/**
* @author hengyunabc
*
*/
public class MethodNameBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
MethodProcessor methodProcessor = bindingContext.getMethodProcessor();
AsmOpUtils.ldc(instructions, methodProcessor.getMethodNode().name);
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(String.class);
}
}

@ -1,41 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LocalVariableNode;
import com.taobao.arthas.bytekit.asm.location.Location;
import com.taobao.arthas.bytekit.asm.location.Location.SyncEnterLocation;
import com.taobao.arthas.bytekit.asm.location.Location.SyncExitLocation;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
public class MonitorBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
Location location = bindingContext.getLocation();
if (location.isWhenComplete()) {
throw new IllegalArgumentException("MonitorBinding only support location whenComplete is false.");
}
if (location instanceof SyncEnterLocation || location instanceof SyncExitLocation) {
LocalVariableNode monitorVariableNode = bindingContext.getMethodProcessor().initMonitorVariableNode();
AsmOpUtils.loadVar(instructions, AsmOpUtils.OBJECT_TYPE, monitorVariableNode.index);
} else {
throw new IllegalArgumentException(
"MonitorBinding only support SyncEnterLocation or SyncExitLocation. location: " + location);
}
}
@Override
public boolean fromStack() {
return true;
}
@Override
public Type getType(BindingContext bindingContext) {
return AsmOpUtils.OBJECT_TYPE;
}
}

@ -1,43 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.LocalVariableNode;
import com.taobao.arthas.bytekit.asm.location.Location;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
public class ReturnBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
//check location
Location location = bindingContext.getLocation();
if (!AsmOpUtils.isReturnCode(location.getInsnNode().getOpcode())) {
throw new IllegalArgumentException("current location is not return location. location: " + location);
}
Type returnType = bindingContext.getMethodProcessor().getReturnType();
if(returnType.equals(Type.VOID_TYPE)) {
AsmOpUtils.push(instructions, null);
}else {
LocalVariableNode returnVariableNode = bindingContext.getMethodProcessor().initReturnVariableNode();
AsmOpUtils.loadVar(instructions, returnType, returnVariableNode.index);
}
}
@Override
public boolean fromStack() {
return true;
}
@Override
public Type getType(BindingContext bindingContext) {
return bindingContext.getMethodProcessor().getReturnType();
}
}

@ -1,23 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
/**
* return/throw/invoke locationlocals
* @author hengyunabc
*
*/
public interface StackSaver {
/**
* 1: 2: callbackstackSaverlocals index
* @param instructions
* @param bindingContext
*/
public void store(InsnList instructions, BindingContext bindingContext);
public void load(InsnList instructions, BindingContext bindingContext);
public Type getType(BindingContext bindingContext);
}

@ -1,18 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
public class ThisBinding extends Binding {
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
bindingContext.getMethodProcessor().loadThis(instructions);
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(Object.class);
}
}

@ -1,30 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
/**
* TODO location
* @author hengyunabc
*
*/
public class ThrowableBinding extends Binding {
@Override
public boolean fromStack() {
return true;
}
@Override
public void pushOntoStack(InsnList instructions, BindingContext bindingContext) {
// TODO 这里从 StackSaver 里取是否合理?
bindingContext.getStackSaver().load(instructions, bindingContext);
// 是否要 check cast ?
}
@Override
public Type getType(BindingContext bindingContext) {
return Type.getType(Throwable.class);
}
}

@ -1,11 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding.annotation;
import java.lang.annotation.Annotation;
import com.taobao.arthas.bytekit.asm.binding.Binding;
public interface BindingParser {
public Binding parse(Annotation annotation);
}

@ -1,15 +0,0 @@
package com.taobao.arthas.bytekit.asm.binding.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.ANNOTATION_TYPE)
public @interface BindingParserHandler {
Class<? extends BindingParser> parser();
}

@ -1,35 +0,0 @@
package com.taobao.arthas.bytekit.asm.inst;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* error hander
*
* interface
*
* desc annotation
*
* NewField fieldfield
* @author hengyunabc
*
*/
@Target({ java.lang.annotation.ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Instrument {
// Instrumentation
// MatchType type() default MatchType.ExactClass;
String[] Class() default {};
String[] BaseClass() default {};
String[] Interface() default {};
String originalName() default "";
Class<? extends Throwable> suppress() default Throwable.class;
Class<?> suppressHandler() default Void.class;
}

@ -1,32 +0,0 @@
package com.taobao.arthas.bytekit.asm.inst;
/**
*
* <pre>
* invokeOrigin()
*
* @Instrument
*
* field @NewField
*
* invokeOrigin() inline
*
*
*
*
*
* </pre>
*
*
*
*
*
* @author hengyunabc 2019-02-25
*
*/
public class InstrumentApi {
public static final <T> T invokeOrigin() {
return null;
}
}

@ -1,10 +0,0 @@
package com.taobao.arthas.bytekit.asm.inst;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ java.lang.annotation.ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface NewField {
}

@ -1,125 +0,0 @@
package com.taobao.arthas.bytekit.asm.inst.impl;
import java.util.List;
import com.alibaba.arthas.deps.org.objectweb.asm.Opcodes;
import com.alibaba.arthas.deps.org.objectweb.asm.Type;
import com.alibaba.arthas.deps.org.objectweb.asm.commons.Method;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.AbstractInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnList;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.InsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodInsnNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodNode;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.TypeInsnNode;
import com.taobao.arthas.bytekit.asm.MethodProcessor;
import com.taobao.arthas.bytekit.utils.AsmOpUtils;
import com.taobao.arthas.bytekit.utils.AsmUtils;
/**
*
* @author hengyunabc 2019-03-15
*
*/
public class InstrumentImpl {
public static MethodNode replaceInvokeOrigin(String originOwner, MethodNode originMethodNode,
MethodNode apmMethodNode) {
// 查找到所有的 InstrumentApi.invokeOrigin() 指令
List<MethodInsnNode> methodInsnNodes = AsmUtils.findMethodInsnNode(apmMethodNode,
"com/taobao/arthas/bytekit/asm/inst/InstrumentApi", "invokeOrigin", "()Ljava/lang/Object;");
Type originReturnType = Type.getMethodType(originMethodNode.desc).getReturnType();
for (MethodInsnNode methodInsnNode : methodInsnNodes) {
InsnList instructions = new InsnList();
AbstractInsnNode secondInsnNode = methodInsnNode.getNext();
// 如果是 非 static ,则要 load this
boolean isStatic = AsmUtils.isStatic(originMethodNode);
int opcode = isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL;
if (!isStatic) {
AsmOpUtils.loadThis(instructions);
}
AsmOpUtils.loadArgs(instructions, originMethodNode);
MethodInsnNode originMethodInsnNode = new MethodInsnNode(opcode, originOwner, originMethodNode.name,
originMethodNode.desc, false);
// 调用原来的函数
instructions.add(originMethodInsnNode);
int sort = originReturnType.getSort();
if (sort == Type.VOID) {
if (secondInsnNode != null) {
if (secondInsnNode.getOpcode() == Opcodes.POP) {
// TODO 原来的函数没有返回值,这里要把 POP去掉。有没有可能是 POP2 ?
apmMethodNode.instructions.remove(secondInsnNode);
} else {
// TODO 原来函数没有返回值,这里有没有可能要赋值??是否要 push null?
AsmOpUtils.pushNUll(instructions);
}
}
} else if (sort >= Type.BOOLEAN && sort <= Type.DOUBLE) {
if (secondInsnNode.getOpcode() == Opcodes.POP) {
// 原来是 pop掉一个栈如果函数返回的是 long则要pop2
if (originReturnType.getSize() == 2) {
apmMethodNode.instructions.insert(secondInsnNode, new InsnNode(Opcodes.POP2));
apmMethodNode.instructions.remove(secondInsnNode);
}
} else {
/**
* castunbox
*
* <pre>
* CHECKCAST java/lang/Integer
* INVOKEVIRTUAL java/lang/Integer.intValue ()I
* </pre>
*/
boolean removeCheckCast = false;
if (secondInsnNode.getOpcode() == Opcodes.CHECKCAST) {
TypeInsnNode typeInsnNode = (TypeInsnNode) secondInsnNode;
// 从原始函数的返回值获取到它对应的自动box的类
Type boxedType = AsmOpUtils.getBoxedType(originReturnType);
if (Type.getObjectType(typeInsnNode.desc).equals(boxedType)) {
AbstractInsnNode thridInsnNode = secondInsnNode.getNext();
if (thridInsnNode != null && thridInsnNode.getOpcode() == Opcodes.INVOKEVIRTUAL) {
MethodInsnNode valueInsnNode = (MethodInsnNode) thridInsnNode;
Method unBoxMethod = AsmOpUtils.getUnBoxMethod(originReturnType);
if (unBoxMethod.getDescriptor().equals(valueInsnNode.desc)
&& valueInsnNode.owner.equals(boxedType.getInternalName())) {
apmMethodNode.instructions.remove(thridInsnNode);
apmMethodNode.instructions.remove(secondInsnNode);
removeCheckCast = true;
}
}
}
}
if (!removeCheckCast) {
// 没有被转换为原始类型也没有pop则说明赋值给了一个对象用类似Long.valudOf转换为Object
AsmOpUtils.box(instructions, originReturnType);
}
}
} else {// ARRAY/OBJECT
// 移掉可能有的 check cast
if (secondInsnNode.getOpcode() == Opcodes.CHECKCAST) {
TypeInsnNode typeInsnNode = (TypeInsnNode) secondInsnNode;
if (Type.getObjectType(typeInsnNode.desc).equals(originReturnType)) {
apmMethodNode.instructions.remove(secondInsnNode);
}
}
}
apmMethodNode.instructions.insertBefore(methodInsnNode, instructions);
apmMethodNode.instructions.remove(methodInsnNode);
}
MethodProcessor methodProcessor = new MethodProcessor(originOwner, apmMethodNode);
methodProcessor.inline(originOwner, originMethodNode);
return apmMethodNode;
}
}

@ -1,52 +0,0 @@
package com.taobao.arthas.bytekit.asm.inst.impl;
import com.alibaba.arthas.deps.org.objectweb.asm.Label;
import com.alibaba.arthas.deps.org.objectweb.asm.tree.MethodNode;
/**
*
* @author hengyunabc 2019-03-18
*
*/
public class MethodReplaceResult {
private boolean success;
private Label start;
private Label end;
private MethodNode methodNode;
public Label getStart() {
return start;
}
public void setStart(Label start) {
this.start = start;
}
public Label getEnd() {
return end;
}
public void setEnd(Label end) {
this.end = end;
}
public MethodNode getMethodNode() {
return methodNode;
}
public void setMethodNode(MethodNode methodNode) {
this.methodNode = methodNode;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}

@ -1,5 +0,0 @@
package com.taobao.arthas.bytekit.asm.interceptor;
public class EnterInteceptor {
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save