Skip to content
Yasumasa Suenaga edited this page Jul 23, 2015 · 3 revisions

CFA - Class File Analyzer

CFAとは?

CFAはクラスファイルに含まれるConstantPoolから以下の情報を取り出すツールです。

  • クラス名
  • それが含まれるファイル名(クラスファイル or アーカイブ(JARなど))
  • スーパークラス名
  • 実装しているインターフェース名
  • クラスファイルバージョン+対応するJREバージョン
  • フィールド定義情報
  • 使用しているメソッド一覧

バイナリダウンロード

使用環境

  • JDK8 ※JREでは動作しません。JDKで提供されるtools.jarを利用します。

起動方法

解析対象ファイルはクラスファイル、JAR、EARなど、Javaクラスのパッケージングとして使えるものを複数指定することができます。

$ java -jar cfa.jar <オプション> <解析対象1> <解析対象2> ...

オプション

  • -h
  • ヘルプメッセージ
  • -t class1,class2,...
  • 解析対象クラスの指定。解析対象ファイルにJAR等を指定した場合、その中で定義されているクラスから、このオプションで指定された文字列を含むクラスのみを解析対象とします。
  • 与える解析対象は複数文字列を指定可能で、デリミタは,(カンマ)です。
  • -c class1,class2,...
  • クラスフィルタ。解析対象ファイルに含まれるクラスのうち、このオプションで指定された文字列を含むクラスに参照のあるもの(指定された文字列を含むクラスを利用しているもの)のみを出力します。
  • 与えるリストは複数文字列を指定可能で、デリミタは,(カンマ)です。
  • -m method1,method2,...
  • メソッドフィルタ。解析対象ファイルに含まれるクラスのうち、このオプションで指定された文字列を含むメソッドに参照のあるもの(指定された文字列を含むメソッドを利用しているもの)のみを出力します。
  • 与えるリストは複数文字列を指定可能で、デリミタは,(カンマ)です。
  • -s
  • ショートモード。ヒットしたクラス名と、それが含まれるアーカイブ名しか出力しません。

出力例

$ java -jar cfa.jar -t JarClassInfoDumper cfa.jar
Name: jp.dip.ysfactory.cfa.JarClassInfoDumper
File: cfa.jar
Super class: java.lang.Object
Interfaces:
  jp.dip.ysfactory.cfa.Dumper
Class version: 52.0 (Java 8)
Field References:
  Ljava.lang.String; jp.dip.ysfactory.cfa.JarClassInfoDumper.fname
Method References:
  java.lang.Object.<init>()V
  java.nio.file.Path.toString()Ljava/lang/String;
  java.util.jar.JarFile.<init>(Ljava/lang/String;)V
  java.util.jar.JarFile.stream()Ljava/util/stream/Stream;
  java.util.stream.Stream.filter(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;
  java.util.stream.Stream.forEach(Ljava/util/function/Consumer;)V
  java.util.jar.JarFile.close()V
  java.lang.Throwable.addSuppressed(Ljava/lang/Throwable;)V
  java.io.IOException.printStackTrace()V
  java.util.jar.JarFile.getInputStream(Ljava/util/zip/ZipEntry;)Ljava/io/InputStream;
  jp.dip.ysfactory.cfa.ClassInfoDumper.<init>(Ljava/io/InputStream;Ljava/lang/String;)V
  jp.dip.ysfactory.cfa.ClassInfoDumper.dumpInfo(Ljp/dip/ysfactory/cfa/Option;)V
  java.io.InputStream.close()V
  java.util.jar.JarEntry.getName()Ljava/lang/String;
  java.lang.String.endsWith(Ljava/lang/String;)Z
  java.util.jar.JarEntry.isDirectory()Z
  java.lang.invoke.LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  jp.dip.ysfactory.cfa.JarClassInfoDumper.lambda$dumpInfo$17(Ljava/util/jar/JarEntry;)Z
  jp.dip.ysfactory.cfa.JarClassInfoDumper.lambda$dumpInfo$18(Ljava/util/jar/JarEntry;)Z
  jp.dip.ysfactory.cfa.JarClassInfoDumper.lambda$dumpInfo$19(Ljava/util/jar/JarFile;Ljp/dip/ysfactory/cfa/Option;Ljava/util/jar/JarEntry;)V

他ツールとの比較

  • jdeps
  • jdepsは一番詳しくてもクラス間の依存性までしか見れません。
  • CFAはjdepsのように依存関係を再帰的に追うことはできません。
  • javap
  • javapは-verboseをつけないとConstantPoolが見えず、出力も冗長になる(バイトコードや例外テーブル等、すべて含まれる)。

想定ユースケース

あるAPIがバグっていて、それをアプリケーションが呼び出していない場合、使用しているライブラリも含めすべての呼び出し元を洗い出したいことがあります。そのようなときにCFAをメソッドフィルタ(-mオプション)とともに使っていただくことで、バイナリから確実に呼び出し元を探し出すことができます。

$ java -jar cfa.jar -m <バグっているAPI> <検索対象ディレクトリ>