Skip to content

Commit

Permalink
handle call in constprop
Browse files Browse the repository at this point in the history
  • Loading branch information
ailrst committed Nov 28, 2023
1 parent c5c6ed4 commit ddb0269
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 28 deletions.
2 changes: 2 additions & 0 deletions src/main/scala/analysis/BasicIRConstProp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@ trait ILValueAnalysisMisc:

case _ => valuelattice.top

val calleePreservedRegisters = Set("R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11")

/** Transfer function for state lattice elements.
*/
def localTransfer(n: IntraProcIRCursor.Node, s: statelattice.Element): statelattice.Element =
n match
case la: LocalAssign =>
s + (la.lhs -> eval(la.rhs, s))
case c: Call => s ++ calleePreservedRegisters.filter(reg => s.keys.exists(_.name == reg)).map(n => Register(n, BitVecType(64)) -> statelattice.sublattice.top).toMap
case _ => s


Expand Down
66 changes: 48 additions & 18 deletions src/main/scala/ir/IRCursor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,56 @@ import cfg_visualiser.DotElement
import cfg_visualiser.{DotArrow, DotGraph, DotInlineArrow, DotInterArrow, DotIntraArrow, DotNode, DotRegularArrow}

import collection.mutable
import scala.annotation.tailrec

/*
* Defines a position in the IL / CFG; this becomes the lhs of the state map lattice in a static analysis.
*/
type CFGPosition = Procedure | Block | Command | ProcedureUnknownJump | ProcedureExit
type CFGPosition = Procedure | Block | Command


// Interprocedural
// position = (call string) + Position



/*
An additional CFG node which implicitly follows the node at `pos`
A call to an unknown procedure without a return to here
Closed trace-perspective beginning of a composite IL structure.
*/
case class ProcedureUnknownJump(fromProcedure: Procedure, pos: CFGPosition)
def begin(c: CFGPosition): CFGPosition = {
c match {
case p:Procedure => p
case b:Block => b
case s:Statement => s.parent.statements.head()
case s:Jump => s
}
}

/*
* An additional CFG node which implicitly follows the node at `pos`
* The exit from a procedure from pos (the last command/jump in the procedure).
Closed trace-perspective end of a composite IL structure.
*/
case class ProcedureExit(fromProcedure: Procedure, pos: CFGPosition)
@tailrec
def end(c: CFGPosition): CFGPosition = {
c match {
case p:Procedure => end(p.returnBlock)
case b:Block => b.jump
case s:Statement => s.parent.statements.back()
case s:Jump => s
}
}


object IntraProcIRCursor {
type Node = CFGPosition

def succ(pos: CFGPosition): Set[CFGPosition] = {
pos match {
case proc: Procedure =>
if proc.entryBlock.isEmpty then Set(proc.returnBlock) else Set(proc.entryBlock.get)
case b: Block =>
if b.statements.isEmpty
then Set.from(b.jumpSet)
else Set[CFGPosition](b.statements.head())
case s: Statement =>
if (s.parent.statements.hasNext(s)) {
Set(s.parent.statements.getNext(s))
Expand All @@ -51,14 +73,6 @@ object IntraProcIRCursor {
case None => Set()
}
}
case b: Block =>
if b.statements.isEmpty
then Set.from(b.jumpSet)
else Set[CFGPosition](b.statements.head())
case proc: Procedure =>
if proc.entryBlock.isEmpty then Set(proc.returnBlock) else Set(proc.entryBlock.get)
case j: ProcedureUnknownJump => Set(ProcedureExit(j.fromProcedure, j))
case e: ProcedureExit => Set()
}
}

Expand All @@ -71,14 +85,30 @@ object IntraProcIRCursor {
Set(s.parent) // predecessor blocks
}
case j: Jump => if j.parent.statements.isEmpty then Set(j.parent) else Set(j.parent.statements.last)
case b: Block => b.predecessors.asInstanceOf[Set[CFGPosition]]
case b: Block => b.predecessors.map(end)
case proc: Procedure => Set() // intraproc
case r: ProcedureUnknownJump => Set(r.pos)
case r: ProcedureExit => Set(r.pos)
}
}
}

object InterProcIRCursor {
type Node = CFGPosition

def succ(pos: CFGPosition): Set[CFGPosition] = {
IntraProcIRCursor.succ(pos) ++ (pos match
case c: DirectCall => Set(c.target)
case _ => Set()
)
}
def pred(pos: CFGPosition): Set[CFGPosition] = {
IntraProcIRCursor.pred(pos) ++ (pos match
case c: Procedure => c.callers().map(end)
case b: Block => if b.isReturn then b.parent.callers().map(end) else Set()
case _ => Set()
)
}
}


def computeDomain(prog: Program): mutable.Set[CFGPosition] = {
val domain : mutable.Set[CFGPosition] = mutable.Set.from(prog.procedures)
Expand Down
10 changes: 3 additions & 7 deletions src/main/scala/translating/BAPToIR.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@ class BAPToIR(var program: BAPProgram, mainAddress: Int) {
var mainProcedure: Option[Procedure] = None
val procedures: ArrayBuffer[Procedure] = ArrayBuffer()
for (s <- program.subroutines) {
//val blocks: mutable.HashSet[Block] = mutable.HashSet[Block]()
//val in: ArrayBuffer[Parameter] = ArrayBuffer()
//val out: ArrayBuffer[Parameter] = ArrayBuffer()
val procedure = Procedure(s.name, Some(s.address), Seq(), Seq(), Seq())

val procedure = Procedure(s.name, Some(s.address))

for (b <- s.blocks) {
val block = Block(b.label, b.address, ArrayBuffer())
Expand All @@ -48,7 +44,7 @@ class BAPToIR(var program: BAPProgram, mainAddress: Int) {
for (b <- s.blocks) {
val block = labelToBlock(b.label)
for (st <- b.statements) {
block.statements.append(translate(st, block))
block.statements.append(translate(st))
}
val (jump, newBlocks) = translate(b.jumps, block)
procedure.addBlocks(newBlocks)
Expand All @@ -65,7 +61,7 @@ class BAPToIR(var program: BAPProgram, mainAddress: Int) {
Program(procedures, mainProcedure.get, memorySections, ArrayBuffer())
}

private def translate(s: BAPStatement, parent: Block) = s match {
private def translate(s: BAPStatement) = s match {
case b: BAPMemAssign => MemoryAssign(b.lhs.toIR, b.rhs.toIR, Some(b.line))
case b: BAPLocalAssign => LocalAssign(b.lhs.toIR, b.rhs.toIR, Some(b.line))
}
Expand Down
5 changes: 2 additions & 3 deletions src/main/scala/translating/ILtoIL.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,9 @@ private class ILSerialiser extends ReadOnlyVisitor {


override def visitGoTo(node: GoTo): GoTo = {
program ++= "NonDetGoTo({"
// TODO
program ++= "GoTo("
program ++= node.targets.map(blockIdentifier).mkString(", ")
program ++= "})" // GoTo
program ++= ")" // GoTo
node
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/scala/util/IntrusiveList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ final class IntrusiveList[T <: IntrusiveListElement] private (var numElems: Int,

override def head(): T = firstElem.get

override def headOption(): Option[T] = firstElem


def begin(): T = firstElem.get

private def containsRef(elem: T): Boolean = {
Expand Down

0 comments on commit ddb0269

Please sign in to comment.