108 lines
3.3 KiB
Scala
108 lines
3.3 KiB
Scala
/*
|
|
* Copyright (c) 2010-2015 SAP SE.
|
|
* 2016-2018 The University of Sheffield.
|
|
*
|
|
* All rights reserved. This program and the accompanying materials
|
|
* This program and the accompanying materials are made
|
|
* available under the terms of the Eclipse Public License 2.0
|
|
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
|
*
|
|
* SPDX-License-Identifier: EPL-2.0
|
|
*/
|
|
|
|
package com.logicalhacking.dasca.crosslanguage.builder.algorithms
|
|
|
|
import scala.collection.JavaConverters.asScalaIteratorConverter
|
|
import scala.collection.mutable.Queue
|
|
import scala.collection.JavaConverters._
|
|
import org.slf4j.LoggerFactory
|
|
import com.ibm.wala.ipa.callgraph.CGNode
|
|
import com.ibm.wala.ipa.callgraph.CallGraph
|
|
import com.ibm.wala.ipa.cfg.BasicBlockInContext
|
|
import com.ibm.wala.ipa.cfg.ExplodedInterproceduralCFG
|
|
import com.ibm.wala.ssa.SSAInstruction
|
|
import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph
|
|
import com.ibm.wala.ssa.analysis.IExplodedBasicBlock
|
|
import com.typesafe.scalalogging.Logger
|
|
import scala.collection.mutable.ListBuffer
|
|
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction
|
|
|
|
abstract class ReachabilityChecker(private val cg: CallGraph, private val keep: CGNode => Boolean) {
|
|
val logger = Logger(LoggerFactory.getLogger(getClass.toString))
|
|
val cache = scala.collection.mutable.Map[(CGNode, CGNode, SSAInstruction), Boolean]()
|
|
|
|
def isReachable(fromNode: CGNode, toNode: CGNode, inst: SSAInstruction): Boolean = {
|
|
if (cache.contains((fromNode, toNode, inst))) return cache((fromNode, toNode, inst))
|
|
|
|
val instructions = if (fromNode == toNode) {
|
|
List(inst)
|
|
} else {
|
|
getReachableInstructions(fromNode, toNode)
|
|
}
|
|
|
|
val ecfg = ExplodedControlFlowGraph.make(fromNode.getIR)
|
|
|
|
val res = instructions.exists { inst => isReachable(ecfg, inst) }
|
|
cache((fromNode, toNode, inst)) = res
|
|
res
|
|
}
|
|
|
|
def getReachableInstructions(fromNode: CGNode, toNode: CGNode): List[SSAInstruction] = {
|
|
val lb = ListBuffer[SSAInstruction]()
|
|
|
|
if (!keep(fromNode) || !keep(toNode)) return List()
|
|
|
|
val queue = Queue[CGNode](toNode)
|
|
val visited = scala.collection.mutable.Set[CGNode]()
|
|
|
|
while (!queue.isEmpty) {
|
|
val cur = queue.dequeue()
|
|
|
|
if (!visited.contains(cur)) {
|
|
visited += cur
|
|
|
|
for (pred <- cg.getPredNodes(cur).asScala ++ extraPredNodes(cur) if keep(pred)) {
|
|
if (pred == fromNode) {
|
|
for (csr <- cg.getPossibleSites(pred, cur).asScala;
|
|
invoke <- pred.getIR.getCalls(csr)) {
|
|
lb += invoke
|
|
}
|
|
} else {
|
|
queue += pred
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
lb.toList
|
|
}
|
|
|
|
private def isReachable(ecfg: ExplodedControlFlowGraph, inst: SSAInstruction): Boolean = {
|
|
ecfg.getBlockForInstruction(inst.iindex)
|
|
|
|
val queue = Queue[IExplodedBasicBlock](ecfg.getBlockForInstruction(inst.iindex))
|
|
val visited = scala.collection.mutable.Set[IExplodedBasicBlock]()
|
|
|
|
while (!queue.isEmpty) {
|
|
val cur = queue.dequeue()
|
|
|
|
if (!visited.contains(cur)) {
|
|
visited += cur
|
|
|
|
if (cur == ecfg.entry())
|
|
return true
|
|
|
|
for (pred <- ecfg.getPredNodes(cur).asScala if canPassThrough(cur, pred)) {
|
|
queue += pred
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
def extraPredNodes(node: CGNode): List[CGNode]
|
|
|
|
def canPassThrough(toBB: IExplodedBasicBlock, predBB: IExplodedBasicBlock): Boolean
|
|
}
|