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
pom.xml.versionsBackup
.pmd
**/.flattened-pom.xml
**/.idea/**
**/cmake-build-debug/**

@ -1,22 +1,18 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"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
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
@ -24,11 +20,12 @@ import java.util.Properties;
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.
*/
private static final String DEFAULT_DOWNLOAD_URL =
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* 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);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
"- ERROR creating output directory '" + outputFile.getParentFile().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 {
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);
ReadableByteChannel rbc;
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/*.deb"
- "packaging/target/*.rpm"
- "tunnel-server/target/*.jar"
- "tunnel-server/target/*fatjar.jar"
skip_cleanup: true
on:
tags: true

@ -141,8 +141,7 @@ chmod +x /tmp/sphinx.osx-x86_64
* 修改`as.sh`里的版本,最后修改日期, `Bootstrap.java`里的版本Dockerfile里的版本
* 修改本地的maven settings.xml
* mvn release:prepare -Darguments="-DskipTests -P full"
* mvn release:perform -Darguments="-DskipTests -P full"
* mvn clean deploy -DskipTests -P full -P release
如果在下载 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
* 需要更新 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
以 3.1.0 版本为例:

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

@ -1,6 +1,6 @@
FROM alpine
ARG ARTHAS_VERSION="3.4.3"
ARG ARTHAS_VERSION="3.5.2"
ARG MIRROR=false
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 telnet and websocket, which enables both local and remote diagnostics with command line and browsers.
* Supports profiler/Flame Graph
* Support get objects in the heap that are instances of the specified class.
* Supports JDK 6+.
* 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)
* [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)
* [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)
* [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.
```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
redefine /tmp/Test.class
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
retransform /tmp/Test.class
retransform -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
```
#### 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
* https://arthas.aliyun.com/doc/en/stack
@ -392,130 +416,21 @@ View profiler results under arthas-output via browser:
### 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)
![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)
![有赞](static/youzan.png)
### Derivative Projects
@ -532,6 +447,7 @@ This project exists, thanks to all the people who contributed.
#### 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.
* [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)

@ -24,6 +24,7 @@ English version goes [here](README.md).
0. 是否有一个全局视角来查看系统的运行状况?
0. 有什么办法可以监控到JVM的实时运行状态
0. 怎么快速定位应用的热点,生成火焰图?
0. 怎样直接从JVM内查找某个类的实例
`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)
* [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?utf8=%E2%9C%93&q=label%3Aquestion-answered+)
* [FAQ/常见问题](https://arthas.aliyun.com/doc/faq)
* [编译调试/参与贡献](https://github.com/alibaba/arthas/blob/master/CONTRIBUTING.md)
* [Release Notes](https://github.com/alibaba/arthas/releases)
* [QQ群/钉钉群](https://arthas.aliyun.com/doc/contact-us.html)
@ -174,14 +175,14 @@ Memory Compiler/内存编译器,编译`.java`文件生成`.class`。
mc /tmp/Test.java
```
#### redefine
* https://arthas.aliyun.com/doc/redefine
#### retransform
* https://arthas.aliyun.com/doc/retransform
加载外部的`.class`文件redefine jvm已加载的类。
加载外部的`.class`文件retransform 热更新jvm已加载的类。
```bash
redefine /tmp/Test.class
redefine -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
retransform /tmp/Test.class
retransform -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
```
#### 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
* https://arthas.aliyun.com/doc/stack
@ -381,132 +403,24 @@ OK
### Known Users
Arthas有超过120家登记用户[查看全部](USERS.md)。
如果您在使用Arthas请让我们知道您的使用对我们非常重要https://github.com/alibaba/arthas/issues/111 (按登记顺序排列)
![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)
![途牛](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)
![有赞](static/youzan.png)
### 生项目
### 衍生项目
* [Bistoury: 一个集成了Arthas的项目](https://github.com/qunarcorp/bistoury)
* [一个使用MVEL脚本的fork](https://github.com/XhinLiang/arthas)
@ -522,6 +436,7 @@ OK
#### Projects
* [bytekit](https://github.com/alibaba/bytekit) Java Bytecode KitArthas里字节码增强的内核。
* [greys-anatomy](https://github.com/oldmanpushcart/greys-anatomy): Arthas代码基于Greys二次开发而来非常感谢Greys之前所有的工作以及Greys原作者对Arthas提出的意见和建议
* [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在这方面所做的优秀工作。

@ -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"?>
<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>
<parent>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId>
<version>3.4.4-SNAPSHOT</version>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>arthas-agent</artifactId>

@ -1,10 +1,10 @@
<?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>
<parent>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId>
<version>3.4.4-SNAPSHOT</version>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>arthas-agent-attach</artifactId>
@ -21,8 +21,6 @@
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.zeroturnaround</groupId>

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

@ -1,11 +1,11 @@
<?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>
<parent>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId>
<version>3.4.4-SNAPSHOT</version>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -39,17 +39,6 @@
<version>${project.version}</version>
</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>
<groupId>org.springframework.boot</groupId>
<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.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.ConfigurableEnvironment;
import com.taobao.arthas.agent.attach.ArthasAgent;
@ -25,6 +26,15 @@ import com.taobao.arthas.agent.attach.ArthasAgent;
public class ArthasConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ArthasConfiguration.class);
@Autowired
ConfigurableEnvironment environment;
/**
* <pre>
* 1. arthas.* Arthas
* 2. ArthasProperties
* </pre>
*/
@ConfigurationProperties(prefix = "arthas")
@ConditionalOnMissingBean
@Bean
@ -36,7 +46,16 @@ public class ArthasConfiguration {
@Bean
public ArthasAgent arthasAgent(@Autowired Map<String, String> arthasConfigMap,
@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());
for (Entry<String, String> entry : arthasConfigMap.entrySet()) {

@ -1,5 +1,7 @@
package com.alibaba.arthas.spring;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
@ -16,6 +18,8 @@ public class ArthasProperties {
private String tunnelServer;
private String agentId;
private String appName;
/**
* report executed command
*/
@ -32,6 +36,20 @@ public class ArthasProperties {
* when arthas agent init error will throw exception by default.
*/
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() {
return home;
@ -105,4 +123,19 @@ public class ArthasProperties {
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
"$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."
rm -r "$DIR/core/src/main/resources/com/taobao/arthas/core/res/version"

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

@ -8,10 +8,10 @@
# program : Arthas
# author : Core Engine @ Taobao.com
# date : 2020-09-27
# date : 2021-06-10
# current arthas script version
ARTHAS_SCRIPT_VERSION=3.4.3
ARTHAS_SCRIPT_VERSION=3.5.2
# SYNOPSIS
# rreadlink <fileOrDirPath>
@ -83,22 +83,27 @@ DIR=$(dirname -- "$(rreadlink "${BASH_SOURCE[0]}")")
ARTHAS_HOME=
# 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_PID=
# target process id to attach
TARGET_IP="127.0.0.1"
# target process id to attach, default 127.0.0.1
TARGET_IP=
DEFAULT_TARGET_IP="127.0.0.1"
# telnet port
TELNET_PORT="3658"
# telnet port, default 3658
TELNET_PORT=
DEFAULT_TELNET_PORT="3658"
# http port
HTTP_PORT="8563"
# http port, default 8563
HTTP_PORT=
DEFAULT_HTTP_PORT="8563"
# telnet session timeout seconds, default 1800
SESSION_TIMEOUT=1800
SESSION_TIMEOUT=
# use specify version
USE_VERSION=
@ -139,6 +144,18 @@ AGENT_ID=
# stat report url
STAT_URL=
# app name
APP_NAME=
# username
USERNAME=
# password
PASSWORD=
# disabledCommands
DISABLED_COMMANDS=
############ Command Arguments ############
# 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
TMP_DIR=/tmp
# last update arthas version
ARTHAS_VERSION=
# arthas remote url
# https://arthas.aliyun.com/download/3.1.7?mirror=aliyun
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_for_env()
{
unset JAVA_TOOL_OPTIONS
# init ARTHAS' lib
mkdir -p "${ARTHAS_LIB_DIR}" \
@ -393,6 +408,9 @@ Usage:
$0 [-h] [--target-ip <value>] [--telnet-port <value>]
[--http-port <value>] [--session-timeout <value>] [--arthas-home <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]
[--attach-only] [-c <value>] [-f <value>] [-v] [pid]
@ -412,6 +430,10 @@ Options and Arguments:
--debug-attach Debug attach agent
--tunnel-server Remote tunnel server url
--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
-c,--command <value> Command to execute, multiple commands separated
by ;
@ -425,15 +447,17 @@ EXAMPLES:
./as.sh <pid>
./as.sh --target-ip 0.0.0.0
./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 --stat-url 'http://192.168.10.11:8080/api/stat'
./as.sh -c 'sysprop; thread' <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 --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
WIKI:
https://arthas.aliyun.com/doc
@ -461,6 +485,33 @@ find_listen_port_process()
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
# Execute commands timeout
STATUS_EXEC_TIMEOUT=100
@ -479,8 +530,8 @@ find_listen_port_process_by_client()
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-client.jar" \
${TARGET_IP} \
${TELNET_PORT} \
$(getTargetIPOrDefault) \
$(getTelnetPortOrDefault) \
-c "session" \
--execution-timeout 2000 \
2>&1
@ -567,6 +618,26 @@ parse_arguments()
shift # past argument
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=true
shift # past argument
@ -637,16 +708,18 @@ parse_arguments()
# check telnet port/http port
local telnetPortPid
local httpPortPid
if [[ $TELNET_PORT > 0 ]]; then
telnetPortPid=$(find_listen_port_process $TELNET_PORT)
local telnetPortOrDefault=$(getTelnetPortOrDefault)
local httpPortOrDefault=$(getHttpPortOrDefault)
if [[ $telnetPortOrDefault > 0 ]]; then
telnetPortPid=$(find_listen_port_process $telnetPortOrDefault)
if [ $telnetPortPid ]; then
echo "[INFO] Process $telnetPortPid already using port $TELNET_PORT"
echo "[INFO] Process $telnetPortPid already using port $telnetPortOrDefault"
fi
fi
if [[ $HTTP_PORT > 0 ]]; then
httpPortPid=$(find_listen_port_process $HTTP_PORT)
if [[ $httpPortOrDefault > 0 ]]; then
httpPortPid=$(find_listen_port_process $httpPortOrDefault)
if [ $telnetPortPid ]; then
echo "[INFO] Process $httpPortPid already using port $HTTP_PORT"
echo "[INFO] Process $httpPortPid already using port $httpPortOrDefault"
fi
fi
@ -668,7 +741,7 @@ parse_arguments()
fi
# check pid
if [ -z ${TARGET_PID} ] && [ ${BATCH_MODE} = false ]; then
if [ -z ${TARGET_PID} ]; then
# interactive mode
local IFS=$'\n'
CANDIDATES=($(call_jps | grep -v sun.tools.jps.Jps | awk '{print $0}'))
@ -717,7 +790,7 @@ parse_arguments()
exit 1
fi
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 "2. Try to use different http port, for example: as.sh --telnet-port 9998 --http-port 9999"
exit 1
@ -759,14 +832,47 @@ attach_jvm()
tempArgs+=("${STAT_URL}")
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[@]}" \
${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-core.jar" \
-pid ${TARGET_PID} \
-target-ip ${TARGET_IP} \
-telnet-port ${TELNET_PORT} \
-http-port ${HTTP_PORT} \
-session-timeout ${SESSION_TIMEOUT} \
"${tempArgs[@]}" \
-core "${arthas_lib_dir}/arthas-core.jar" \
-agent "${arthas_lib_dir}/arthas-agent.jar"
@ -811,7 +917,7 @@ sanity_check() {
}
port_pid_check() {
if [[ $TELNET_PORT > 0 ]]; then
if [[ $(getTelnetPortOrDefault) > 0 ]]; then
local telnet_output
local find_process_status
# declare local var before var=$()
@ -844,15 +950,15 @@ port_pid_check() {
}
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] 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"
}
print_telnet_port_used_error() {
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"
}
@ -881,16 +987,16 @@ active_console()
if [ "${COMMAND}" ] ; then
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-client.jar" \
${TARGET_IP} \
${TELNET_PORT} \
$(getTargetIPOrDefault) \
$(getTelnetPortOrDefault) \
"${tempArgs[@]}" \
-c "${COMMAND}"
fi
if [ "${BATCH_FILE}" ] ; then
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
-jar "${arthas_lib_dir}/arthas-client.jar" \
${TARGET_IP} \
${TELNET_PORT} \
$(getTargetIPOrDefault) \
$(getTelnetPortOrDefault) \
"${tempArgs[@]}" \
-f ${BATCH_FILE}
fi
@ -899,12 +1005,12 @@ active_console()
if [[ $(command -v telnet) == *"system32"* ]] ; then
# 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 "Please start cmd.exe from Windows start menu, and then run telnet ${TARGET_IP} ${TELNET_PORT} to connect to target process."
echo "Or visit http://127.0.0.1:${HTTP_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:$(getHttpPortOrDefault) to connect to target process."
return 1
fi
echo "telnet connecting to arthas server... current timestamp is `date +%s`"
telnet ${TARGET_IP} ${TELNET_PORT}
telnet $(getTargetIPOrDefault) $(getTelnetPortOrDefault)
else
echo "'telnet' is required." 1>&2
return 1

@ -1,10 +1,10 @@
<?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>
<parent>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-all</artifactId>
<version>3.4.4-SNAPSHOT</version>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>arthas-boot</artifactId>

@ -1,5 +1,8 @@
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.File;
import java.io.IOException;
@ -11,12 +14,12 @@ import java.security.CodeSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.InputMismatchException;
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.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
*
@ -47,15 +47,17 @@ import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT;
@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"
+ " 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 --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 -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 --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 --disabled-commands stop,dump\n"
+ " java -jar arthas-boot.jar --repo-mirror aliyun --use-http\n" + "WIKI:\n"
+ " https://arthas.aliyun.com/doc\n")
public class Bootstrap {
@ -67,9 +69,9 @@ public class Bootstrap {
private boolean help = false;
private long pid = -1;
private String targetIp = DEFAULT_TARGET_IP;
private int telnetPort = DEFAULT_TELNET_PORT;
private int httpPort = DEFAULT_HTTP_PORT;
private String targetIp;
private Integer telnetPort;
private Integer httpPort;
/**
* @see com.taobao.arthas.core.config.Configure#DEFAULT_SESSION_TIMEOUT_SECONDS
*/
@ -118,13 +120,26 @@ public class Bootstrap {
private String tunnelServer;
private String agentId;
private String appName;
private String username;
private String password;
private String statUrl;
private String select;
private String disabledCommands;
static {
ARTHAS_LIB_DIR = new File(
System.getProperty("user.home") + File.separator + ".arthas" + File.separator + "lib");
String arthasLibDirEnv = System.getenv("ARTHAS_LIB_DIR");
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 {
ARTHAS_LIB_DIR.mkdirs();
} catch (Throwable t) {
@ -258,6 +273,23 @@ public class Bootstrap {
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")
@Description("The report stat url")
public void setStatUrl(String statUrl) {
@ -270,6 +302,12 @@ public class Bootstrap {
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,
ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
@ -325,16 +363,16 @@ public class Bootstrap {
// check telnet/http port
long telnetPortPid = -1;
long httpPortPid = -1;
if (bootstrap.getTelnetPort() > 0) {
telnetPortPid = SocketUtils.findTcpListenProcess(bootstrap.getTelnetPort());
if (bootstrap.getTelnetPortOrDefault() > 0) {
telnetPortPid = SocketUtils.findTcpListenProcess(bootstrap.getTelnetPortOrDefault());
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) {
httpPortPid = SocketUtils.findTcpListenProcess(bootstrap.getHttpPort());
if (bootstrap.getHttpPortOrDefault() > 0) {
httpPortPid = SocketUtils.findTcpListenProcess(bootstrap.getHttpPortOrDefault());
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) {
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.",
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);
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 {
//double check telnet port and pid before attach
telnetPortPid = findProcessByTelnetClient(arthasHomeDir.getAbsolutePath(), bootstrap.getTelnetPort());
telnetPortPid = findProcessByTelnetClient(arthasHomeDir.getAbsolutePath(), bootstrap.getTelnetPortOrDefault());
checkTelnetPortPid(bootstrap, telnetPortPid, pid);
// start arthas-core.jar
@ -473,12 +511,21 @@ public class Bootstrap {
attachArgs.add(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath());
attachArgs.add("-pid");
attachArgs.add("" + pid);
attachArgs.add("-target-ip");
attachArgs.add(bootstrap.getTargetIp());
attachArgs.add("-telnet-port");
attachArgs.add("" + bootstrap.getTelnetPort());
attachArgs.add("-http-port");
attachArgs.add("" + bootstrap.getHttpPort());
if (bootstrap.getTargetIp() != null) {
attachArgs.add("-target-ip");
attachArgs.add(bootstrap.getTargetIp());
}
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(new File(arthasHomeDir, "arthas-core.jar").getAbsolutePath());
attachArgs.add("-agent");
@ -488,6 +535,20 @@ public class Bootstrap {
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) {
attachArgs.add("-tunnel-server");
attachArgs.add(bootstrap.getTunnelServer());
@ -501,6 +562,11 @@ public class Bootstrap {
attachArgs.add(bootstrap.getStatUrl());
}
if (bootstrap.getDisabledCommands() != null){
attachArgs.add("-disabled-commands");
attachArgs.add(bootstrap.getDisabledCommands());
}
AnsiLog.info("Try to attach process " + pid);
AnsiLog.debug("Start arthas-core.jar args: " + attachArgs);
ProcessUtils.startArthasCore(pid, attachArgs);
@ -538,10 +604,10 @@ public class Bootstrap {
}
// telnet port ,ip
telnetArgs.add(bootstrap.getTargetIp());
telnetArgs.add("" + bootstrap.getTelnetPort());
telnetArgs.add(bootstrap.getTargetIpOrDefault());
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);
// 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) {
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.",
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.",
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");
System.exit(1);
}
@ -704,14 +770,38 @@ public class Bootstrap {
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;
}
public int getTelnetPortOrDefault() {
if (this.telnetPort == null) {
return DEFAULT_TELNET_PORT;
} else {
return this.telnetPort;
}
}
public int getHttpPort() {
public Integer getHttpPort() {
return httpPort;
}
public int getHttpPortOrDefault() {
if (this.httpPort == null) {
return DEFAULT_HTTP_PORT;
} else {
return this.httpPort;
}
}
public String getCommand() {
return command;
}
@ -760,6 +850,10 @@ public class Bootstrap {
return agentId;
}
public String getAppName() {
return appName;
}
public String getStatUrl() {
return statUrl;
}
@ -767,4 +861,16 @@ public class Bootstrap {
public String getSelect() {
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()) {
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;
}
@ -233,13 +233,13 @@ public class ProcessUtils {
String javaHome = findJavaHome();
// find java/java.exe
File javaPath = findJava();
File javaPath = findJava(javaHome);
if (javaPath == null) {
throw new IllegalArgumentException(
"Can not find java/java.exe executable file under java home: " + javaHome);
}
File toolsJar = findToolsJar();
File toolsJar = findToolsJar(javaHome);
if (JavaVersionUtils.isLessThanJava9()) {
if (toolsJar == null || !toolsJar.exists()) {
@ -313,8 +313,8 @@ public class ProcessUtils {
// find arthas-client.jar
URLClassLoader classLoader = new URLClassLoader(
new URL[]{new File(arthasHomeDir, "arthas-client.jar").toURI().toURL()});
Class<?> telnetConsoleClas = classLoader.loadClass("com.taobao.arthas.client.TelnetConsole");
Method processMethod = telnetConsoleClas.getMethod("process", String[].class);
Class<?> telnetConsoleClass = classLoader.loadClass("com.taobao.arthas.client.TelnetConsole");
Method processMethod = telnetConsoleClass.getMethod("process", String[].class);
//redirect System.out/System.err
PrintStream originSysOut = System.out;
@ -354,8 +354,7 @@ public class ProcessUtils {
}
}
private static File findJava() {
String javaHome = findJavaHome();
private static File findJava(String javaHome) {
String[] paths = { "bin/java", "bin/java.exe", "../bin/java", "../bin/java.exe" };
List<File> javaList = new ArrayList<File>();
@ -389,12 +388,11 @@ public class ProcessUtils {
return javaList.get(0);
}
private static File findToolsJar() {
private static File findToolsJar(String javaHome) {
if (JavaVersionUtils.isGreaterThanJava8()) {
return null;
}
String javaHome = findJavaHome();
File toolsJar = new File(javaHome, "lib/tools.jar");
if (!toolsJar.exists()) {
toolsJar = new File(javaHome, "../lib/tools.jar");

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