Skip to content

Instantly share code, notes, and snippets.

@RainWarrior
Created March 28, 2014 10:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RainWarrior/9829592 to your computer and use it in GitHub Desktop.
Save RainWarrior/9829592 to your computer and use it in GitHub Desktop.
// GPL3+
package asmstuff
import collection.JavaConversions._
import org.objectweb.asm._
import tree._
import java.nio.file._
import attribute.BasicFileAttributes
import java.net.URI
object Usage {
var found = Set.empty[(ClassNode, MethodNode)]
def find(
node: ClassNode,
ct: String => Boolean,
ft: (String, String) => Boolean,
mt: (String, String, String) => Boolean
) {
def printm(m: MethodNode) = if(!found((node, m))) {
println(s"${node.name}/${m.name}${m.desc}")
found += ((node, m))
}
def checkFieldDesc(desc: String, m: MethodNode) = {
val cls = Type.getType(desc)
cls.getSort match {
case Type.ARRAY =>
if(cls.getElementType.getSort == Type.OBJECT)
if(ct(cls.getElementType.getInternalName)) printm(m)
case Type.OBJECT =>
if(ct(cls.getInternalName)) printm(m)
case _ =>
}
}
def checkMethodDesc(desc: String, m: MethodNode) = {
val tpe = Type.getType(desc)
for(d <- tpe.getArgumentTypes) checkFieldDesc(d.getDescriptor, m)
checkFieldDesc(tpe.getReturnType.getDescriptor, m)
}
for {
m <- node.methods
insn <- m.instructions.iterator
} insn match {
case n: FieldInsnNode =>
if(ct(n.owner)) printm(m)
if(ft(n.owner, n.name)) printm(m)
case n: FrameNode =>
case n: IincInsnNode =>
case n: InsnNode =>
case n: IntInsnNode =>
case n: InvokeDynamicInsnNode => // Hmm
case n: JumpInsnNode =>
case n: LabelNode =>
case n: LdcInsnNode => n.cst match {
case cst: Type => if(ct(cst.getInternalName)) printm(m) // No method types/handles
case _ =>
}
case n: LineNumberNode =>
case n: LookupSwitchInsnNode =>
case n: MethodInsnNode =>
if(ct(n.owner)) printm(m)
checkMethodDesc(n.desc, m)
if(mt(n.owner, n.name, n.desc)) printm(m)
case n: MultiANewArrayInsnNode =>
checkFieldDesc(n.desc, m)
case n: TableSwitchInsnNode =>
case n: TypeInsnNode =>
if(ct(n.desc)) printm(m)
case n: VarInsnNode =>
case _ =>
}
}
def main(args: Array[String]) {
var ct: String => Boolean = (_ => false)
var ft: (String, String) => Boolean = (_, _) => false
var mt: (String, String, String) => Boolean = (_, _, _) => false
if(args.length < 1 || (args.length % 2 != 1)) {
println("usage: program <jar> [(-c/-f/-m) name]+")
return
}
for(aa <- args.tail.grouped(2)) {
val Array(t, a) = aa
t match {
case "-c" =>
val oct = ct
val nct = { (c: String) =>
if(c == a) true
else oct(c)
}
ct = nct
case "-f" =>
val oft = ft
val nft = { (o: String, n: String) =>
if(s"$o/$n" == a) true
else oft(o, n)
}
ft = nft
case "-m" =>
val omt = mt
val nmt = { (o: String, n: String, d: String) =>
if(s"$o/$n$d" == a) true
else omt(o, n, d)
}
mt = nmt
}
}
val jar = Paths.get(args.head)
val uri = URI.create("jar:file:" + jar.toUri.getPath)
val fs = FileSystems.newFileSystem(uri, Map("create" -> "false"))
Files.walkFileTree(fs.getPath("/"), new SimpleFileVisitor[Path] {
override def visitFile(path: Path, attrs: BasicFileAttributes) = {
if(path.toString.endsWith(".class")) {
val s = Files.newInputStream(path)
val cr = new ClassReader(s)
val n = new ClassNode
cr.accept(n, 0)
s.close()
find(n, ct, ft, mt)
}
FileVisitResult.CONTINUE
}
})
fs.close()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment