WALA ってなぁに?
WALA (T.J. Watson Libraries for Analysis) は、IBMによって開発された主にJavaとJavaScriptのコードを解析するためのJava向けライブラリです。
Git Hub : https://github.com/wala/WALA
提供されている機能
- プログラム内のクラスや関数の依存関係をグラフ化
- クラス構造やメソッド情報の抽出
- バイトコードとプログラムの間の表現(3アドレスコード)に変換
- 値やオブジェクトの動きを追跡
- 変数の参照先を調べる
etc...
WALA の使い方
WALA の使い方を説明するために、定義されているクラスにあるメソッドの一覧を出力するプログラムを作成していきます。
WALA を利用するために以下の環境を用意します。
- Java : Java 21
- ビルドツール : Gradle
- エディタ : IntelliJ IDEA
build.gradle
plugins {
id 'java'
id 'application'
}
repositories {
mavenCentral()
}
// Walaのバージョン
def walaVersion = '1.6.3'
// プロジェクトの依存関係
dependencies {
// Walaのコアライブラリ
implementation "com.ibm.wala:com.ibm.wala.core:${walaVersion}"
// Shrike: Walaが内部で利用するバイトコード操作ライブラリ
implementation "com.ibm.wala:com.ibm.wala.shrike:${walaVersion}"
// Walaの共通ユーティリティ
implementation "com.ibm.wala:com.ibm.wala.util:${walaVersion}"
}
そして、解析対象のJavaファイルはこれです。このファイルをclassファイルにしてください。
TargetApp.java
public class TargetApp {
public static void main(String[] args) {
int result = add(5, 10);
printMessage("Result is: " + result);
}
public static int add(int a, int b) {
return a + b;
}
public static void printMessage(String message) {
if (message != null) {
System.out.println(message);
}
}
}
そして、Main.javaでWALAを用いたClass解析を行います。
Main.java
package org.example;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.ShrikeCTMethod;
import com.ibm.wala.core.util.config.AnalysisScopeReader;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.ClassHierarchyFactory;
import com.ibm.wala.shrike.shrikeBT.IInstruction;
import com.ibm.wala.shrike.shrikeCT.InvalidClassFileException;
import com.ibm.wala.util.WalaException;
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException, WalaException, InvalidClassFileException {
// 1. 解析対象のクラスファイルへのパスを指定
File targetClassFile = new File("compiled_classes/TargetApp.class");
if (!targetClassFile.exists()) {
System.err.println("Target class file not found: " + targetClassFile.getAbsolutePath());
return;
}
// 2. 解析スコープ(AnalysisScope)の作成
// 解析の対象範囲(どのクラスを解析するか)を定義。
AnalysisScopeReader scopeReader = new AnalysisScopeReader(){};
AnalysisScope scope = scopeReader.makeJavaBinaryAnalysisScope(targetClassFile.getAbsolutePath(), null);
// 3. クラス階層(ClassHierarchy)の構築
// 解析スコープ内のクラス間の継承関係などを解決。
ClassHierarchy cha = ClassHierarchyFactory.make(scope);
// 4. 解析と結果の出力
for (IClass aClass : cha) {
// "L"で始まり、"TargetApp"を含むクラス名に絞り込み
// Walaのクラス名は "L<パッケージ>/<クラス名>" という形式になる。
String className = aClass.getName().toString();
if (className.contains("TargetApp")) {
System.out.println("Class: " + className);
// クラス内の全メソッドをループ
for (IMethod method : aClass.getDeclaredMethods()) {
// ShrikeCT/BTを使ってバイトコード命令を取得
// IMethodがShrikeMethodであることを確認
if (method instanceof ShrikeCTMethod) {
IInstruction[] instructions = ((ShrikeCTMethod) method).getInstructions();
System.out.printf(" - Method: %s, Bytecode instructions: %d%n",
method.getName().toString(),
instructions != null ? instructions.length : 0);
}
}
}
}
}
}
Main.javaを実行すると、このような結果が出力されます。
このように、WALAを利用するとJavaのコードの構造やデータを解析できます。
