From 4492847e0a779141c26a3c747256a693c2cf4056 Mon Sep 17 00:00:00 2001 From: rina Date: Wed, 10 Apr 2024 15:15:29 +1000 Subject: [PATCH 1/7] patch format_adt.py for aslt format. aslt is almost python. this adds support for semicolon separation, single-quote strings, and adds rules for line breaking aslt stmt/exprs. --- scripts/format_adt.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/format_adt.py b/scripts/format_adt.py index 3a9da6a74..9f8eacfac 100755 --- a/scripts/format_adt.py +++ b/scripts/format_adt.py @@ -40,7 +40,7 @@ notspace_re = re.compile(rb'\S') head_re = re.compile(rb'[^\s(]+') num_re = re.compile(rb'[_0-9xa-fA-F]+') -string_re = re.compile(rb'"(?:[^"\\]|\\.)*"') +string_re = re.compile(rb'''"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*\'''') @dataclasses.dataclass class Context: @@ -79,8 +79,8 @@ def pretty(outfile, data: bytes, spaces: int): assert m outfile.write(m[0]) i = m.end(0) - elif c == b',': - outfile.write(b',') + elif c in b',;': + outfile.write(c) i += 1 if stack[-1].multiline: outfile.write(b'\n') @@ -97,11 +97,14 @@ def pretty(outfile, data: bytes, spaces: int): outfile.write(c) i += 1 islist = c == b'[' and ']' != chr(data[i]) - multiline = islist or head in (b'Project', b'Def', b'Goto', b'Call', b'Sub', b'Blk', b'Arg') + multiline = islist or head in (b'Project', b'Def', b'Goto', b'Call', b'Sub', b'Blk', b'Arg') or head.startswith(b'Stmt_') or head in (b'Expr_TApply', b'Expr_Slices') if multiline: depth += 1 - outfile.write(b'\n') - outfile.write(indent * depth) + if islist and stack and stack[-1].multiline: + outfile.write(indent[1:]) + else: + outfile.write(b'\n') + outfile.write(indent * depth) stack.append(Context(i, flip[c], multiline)) elif c in b')]': @@ -115,7 +118,7 @@ def pretty(outfile, data: bytes, spaces: int): depth -= 1 if not stack: outfile.write(b'\n') - elif c == b'"': + elif c in b'"\'': string = string_re.match(data, i) if not string: raise ValueError(f"unclosed string beginning at byte {i+1}.") From 9cab1025c46aa97fa225ca0009ce8f5302e05471 Mon Sep 17 00:00:00 2001 From: Alistair Michael Date: Tue, 16 Apr 2024 15:23:09 +1000 Subject: [PATCH 2/7] registers in spec --- .../translating/SpecificationLoader.scala | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/main/scala/translating/SpecificationLoader.scala b/src/main/scala/translating/SpecificationLoader.scala index 29aaa5587..1d9b82336 100644 --- a/src/main/scala/translating/SpecificationLoader.scala +++ b/src/main/scala/translating/SpecificationLoader.scala @@ -318,7 +318,11 @@ case class SpecificationLoader(symbols: Set[SpecGlobal], program: Program) { def visitId(ctx: IdContext, nameToGlobals: Map[String, SpecGlobal], params: Map[String, Parameter] = Map()): BExpr = { val id = ctx.getText - if (id.startsWith("Gamma_")) { + id match { + case id if id.startsWith("Gamma_R") => { + BVariable(id, BoolBType, Scope.Global) + } + case id if (id.startsWith("Gamma_")) => { val gamma_id = id.stripPrefix("Gamma_") params.get(gamma_id) match { case Some(p: Parameter) => p.value.toGamma @@ -327,26 +331,31 @@ case class SpecificationLoader(symbols: Set[SpecGlobal], program: Program) { case Some(g: SpecGlobal) => SpecGamma(g) case None => throw new Exception(s"unresolvable reference to '$id' in specification") } + } + } + case id if id.startsWith("R") => { + BVariable(id, BitVecBType(64), Scope.Global) + } + case id => { + params.get(id) match { + case Some(p: Parameter) => + val registerSize = p.value.size + val paramSize = p.size + if (paramSize == registerSize) { + p.value.toBoogie + } else if (registerSize > paramSize) { + BVExtract(registerSize - p.size, 0, p.value.toBoogie) + } else { + throw Exception(s"parameter $p doesn't fit in register ${p.value} for ID $id") + } + case None => + nameToGlobals.get(ctx.getText) match { + case Some(g: SpecGlobal) => g + case None => throw new Exception(s"unresolvable reference to '$id' in specification") + } + } } - } else { - params.get(id) match { - case Some(p: Parameter) => - val registerSize = p.value.size - val paramSize = p.size - if (paramSize == registerSize) { - p.value.toBoogie - } else if (registerSize > paramSize) { - BVExtract(registerSize - p.size, 0, p.value.toBoogie) - } else { - throw Exception(s"parameter $p doesn't fit in register ${p.value} for ID $id") - } - case None => - nameToGlobals.get(ctx.getText) match { - case Some(g: SpecGlobal) => g - case None => throw new Exception(s"unresolvable reference to '$id' in specification") - } } - } } def visitMulDivModOp(ctx: MulDivModOpContext): BVBinOp = ctx.getText match { From d60e1060f536d92895b3df9e4a61756235e09346 Mon Sep 17 00:00:00 2001 From: l-kent Date: Tue, 7 May 2024 09:16:35 +1000 Subject: [PATCH 3/7] fix issue with intrusivelist splitOn method --- src/main/scala/ir/IRCursor.scala | 6 ++--- src/main/scala/ir/Program.scala | 3 +-- src/main/scala/translating/GTIRBToIR.scala | 10 +++---- src/main/scala/translating/IRToBoogie.scala | 2 +- .../util/intrusive_list/IntrusiveList.scala | 26 ++++++++----------- .../IntrusiveListPublicInterfaceTest.scala | 3 +-- 6 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/main/scala/ir/IRCursor.scala b/src/main/scala/ir/IRCursor.scala index 7acd268a3..2b5d3123e 100644 --- a/src/main/scala/ir/IRCursor.scala +++ b/src/main/scala/ir/IRCursor.scala @@ -46,8 +46,8 @@ object IRWalk: def commandBegin(pos: CFGPosition) : Option[Command] = { pos match { - case p: Procedure => p.entryBlock.map(b => b.statements.headOption().getOrElse(b.jump)) - case b: Block => Some(b.statements.headOption().getOrElse(b.jump)) + case p: Procedure => p.entryBlock.map(b => b.statements.headOption.getOrElse(b.jump)) + case b: Block => Some(b.statements.headOption.getOrElse(b.jump)) case c: Command => Some(c) } } @@ -81,7 +81,7 @@ trait IntraProcIRCursor extends IRWalk[CFGPosition, CFGPosition] { def succ(pos: CFGPosition): Set[CFGPosition] = { pos match { case proc: Procedure => proc.entryBlock.toSet - case b: Block => Set(b.statements.headOption().getOrElse(b.jump)) + case b: Block => Set(b.statements.headOption.getOrElse(b.jump)) case s: Statement => Set(s.succ().getOrElse(s.parent.jump)) case n: GoTo => n.targets.asInstanceOf[Set[CFGPosition]] case c: Call => c.parent.fallthrough.toSet diff --git a/src/main/scala/ir/Program.scala b/src/main/scala/ir/Program.scala index 4e8f18b00..ee9635150 100644 --- a/src/main/scala/ir/Program.scala +++ b/src/main/scala/ir/Program.scala @@ -358,9 +358,8 @@ class Block private ( statements.onInsert = x => x.setParent(this) statements.onRemove = x => x.deParent() - def this(label: String, address: Option[Int] = None, statements: IterableOnce[Statement] = Set.empty, jump: Jump = GoTo(Set.empty)) = { - this(label, address, IntrusiveList.from(statements), jump, mutable.HashSet.empty, None) + this(label, address, IntrusiveList.from(statements), jump, mutable.HashSet.empty, None) } def jump: Jump = _jump diff --git a/src/main/scala/translating/GTIRBToIR.scala b/src/main/scala/translating/GTIRBToIR.scala index b4b6f5e31..fa33bb147 100644 --- a/src/main/scala/translating/GTIRBToIR.scala +++ b/src/main/scala/translating/GTIRBToIR.scala @@ -292,7 +292,7 @@ class GTIRBToIR(mods: Seq[Module], parserMap: immutable.Map[String, Array[Array[ private def cleanUpIfPCAssign(block: Block, procedure: Procedure): Unit = { var newBlockCount = 0 var currentBlock = block - var currentStatement = currentBlock.statements.head() + var currentStatement = currentBlock.statements.head var breakLoop = false val queue = mutable.Queue[Block]() while (!breakLoop) { @@ -306,7 +306,7 @@ class GTIRBToIR(mods: Seq[Module], parserMap: immutable.Map[String, Array[Array[ if (queue.nonEmpty) { currentBlock = queue.dequeue() - currentStatement = currentBlock.statements.head() + currentStatement = currentBlock.statements.head } else { breakLoop = true } @@ -326,7 +326,7 @@ class GTIRBToIR(mods: Seq[Module], parserMap: immutable.Map[String, Array[Array[ if (queue.nonEmpty) { currentBlock = queue.dequeue() - currentStatement = currentBlock.statements.head() + currentStatement = currentBlock.statements.head } else { breakLoop = true } @@ -335,7 +335,7 @@ class GTIRBToIR(mods: Seq[Module], parserMap: immutable.Map[String, Array[Array[ currentStatement = currentBlock.statements.getNext(currentStatement) } else if (queue.nonEmpty) { currentBlock = queue.dequeue() - currentStatement = currentBlock.statements.head() + currentStatement = currentBlock.statements.head } else { breakLoop = true } @@ -374,7 +374,7 @@ class GTIRBToIR(mods: Seq[Module], parserMap: immutable.Map[String, Array[Array[ g.targets.head } else { // case where goto has multiple targets: create an extra block and point to that - val afterBlock = Block(parentLabel + "$__" + newBlockCount, None) + val afterBlock = Block(parentLabel + "$__" + newBlockCount) newBlockCount += 1 newBlocks.append(afterBlock) afterBlock.replaceJump(currentBlock.jump) diff --git a/src/main/scala/translating/IRToBoogie.scala b/src/main/scala/translating/IRToBoogie.scala index 3a88a1f64..51a820273 100644 --- a/src/main/scala/translating/IRToBoogie.scala +++ b/src/main/scala/translating/IRToBoogie.scala @@ -637,7 +637,7 @@ class IRToBoogie(var program: Program, var spec: Specification) { case g: GoTo => // collects all targets of the goto with a branch condition that we need to check the security level for // and collects the variables for that - val conditions = g.targets.flatMap(_.statements.headOption()).collect { case a: Assume if a.checkSecurity => a } + val conditions = g.targets.flatMap(_.statements.headOption.collect { case a: Assume if a.checkSecurity => a }) val conditionVariables = conditions.flatMap(_.body.variables) val gammas = conditionVariables.map(_.toGamma).toList.sorted val conditionAssert: List[BCmd] = if (gammas.size > 1) { diff --git a/src/main/scala/util/intrusive_list/IntrusiveList.scala b/src/main/scala/util/intrusive_list/IntrusiveList.scala index 2803cf931..22d9f6323 100644 --- a/src/main/scala/util/intrusive_list/IntrusiveList.scala +++ b/src/main/scala/util/intrusive_list/IntrusiveList.scala @@ -1,5 +1,6 @@ package util.intrusive_list import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer // TODO: implement IterableOps // So need iterablefactory https://docs.scala-lang.org/overviews/core/custom-collections.html @@ -90,7 +91,7 @@ final class IntrusiveList[T <: IntrusiveListElement[T]] private ( elem } - class IntrusiveListIterator(var elem: Option[T], forward: Boolean) extends Iterator[T] { + private class IntrusiveListIterator(var elem: Option[T], forward: Boolean) extends Iterator[T] { override def hasNext: Boolean = elem.isDefined override def next: T = { val t = elem.get @@ -133,14 +134,14 @@ final class IntrusiveList[T <: IntrusiveListElement[T]] private ( /** * Unsafely return the first element of the list. */ - override def head(): T = firstElem.get + override def head: T = firstElem.get - override def headOption(): Option[T] = firstElem + override def headOption: Option[T] = firstElem /** * Unsafely return the first element of the list. */ - def begin(): T = firstElem.get + def begin: T = firstElem.get /** * Check whether the list contains the given element (by reference) by linear scan. @@ -169,7 +170,7 @@ final class IntrusiveList[T <: IntrusiveListElement[T]] private ( /** * Unsafely return the last element of the list. */ - def back(): T = lastElem.get + def back: T = lastElem.get /** * Add an element to the beginning of the list. @@ -232,19 +233,19 @@ final class IntrusiveList[T <: IntrusiveListElement[T]] private ( } /** - * Split the list into two lists, the first retains all elements up to to and including the provided element, - * and and returns the second list from the element until the end. + * Removes all elements after the provided element n and returns an ArrayBuffer containing the removed elements, + * maintaining the ordering. * * @param n The element to split on, remains in the first list. - * @return A list containing all elements after n. + * @return An ArrayBuffer containing all elements after n. */ - def splitOn(n: T): IntrusiveList[T] = { + def splitOn(n: T): ArrayBuffer[T] = { require(!lastElem.contains(n)) require(containsRef(n)) val ne = n.next - val newlist = new IntrusiveList[T]() + val newlist = ArrayBuffer[T]() var next = n.next while (next.isDefined) { remove(next.get) @@ -355,9 +356,6 @@ final class IntrusiveList[T <: IntrusiveListElement[T]] private ( } object IntrusiveList { - - def from[T <: IntrusiveListElement[T]](it: IntrusiveList[T]): IntrusiveList[T] = it - def from[T <: IntrusiveListElement[T]](it: IterableOnce[T]): IntrusiveList[T] = IntrusiveList[T]().addAll(it) def empty[T <: IntrusiveListElement[T]]: IntrusiveList[T] = new IntrusiveList[T]() @@ -382,8 +380,6 @@ trait IntrusiveListElement[T <: IntrusiveListElement[T]]: elem } - - private[intrusive_list] final def unitary: Boolean = next.isEmpty && prev.isEmpty private[intrusive_list] final def insertAfter(elem: T): T = { diff --git a/src/test/scala/util/intrusive_list/IntrusiveListPublicInterfaceTest.scala b/src/test/scala/util/intrusive_list/IntrusiveListPublicInterfaceTest.scala index 06c3ffcb2..5334181a0 100644 --- a/src/test/scala/util/intrusive_list/IntrusiveListPublicInterfaceTest.scala +++ b/src/test/scala/util/intrusive_list/IntrusiveListPublicInterfaceTest.scala @@ -184,8 +184,7 @@ class IntrusiveListPublicInterfaceTest extends AnyFunSuite { test("construct") { val l = getSequentialList(3) - - + val l2 = IntrusiveList.from(l) assert(l2.size == 3) From d3844d191eba76aa2c5bbd32736dffa7140342ad Mon Sep 17 00:00:00 2001 From: l-kent Date: Tue, 7 May 2024 09:17:14 +1000 Subject: [PATCH 4/7] fix issue with returnTarget being mutable and having unnecessary invariant --- src/main/scala/ir/Statement.scala | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/main/scala/ir/Statement.scala b/src/main/scala/ir/Statement.scala index 8cbd55952..5ad925637 100644 --- a/src/main/scala/ir/Statement.scala +++ b/src/main/scala/ir/Statement.scala @@ -127,21 +127,7 @@ object GoTo: sealed trait Call extends Jump { - private var _returnTarget: Option[Block] = None - - // replacing the return target of a call - def returnTarget_=(b: Block): Unit = { - require(b.hasParent) - - if (hasParent) { - // if we don't have a parent now, delay adding the fallthrough block until linking - parent.fallthrough = Some(GoTo(Set(b))) - } - - _returnTarget = Some(b) - } - - def returnTarget: Option[Block] = _returnTarget + val returnTarget: Option[Block] // moving a call between blocks override def linkParent(p: Block): Unit = { @@ -154,10 +140,9 @@ sealed trait Call extends Jump { } class DirectCall(val target: Procedure, - private val _returnTarget: Option[Block] = None, + override val returnTarget: Option[Block] = None, override val label: Option[String] = None ) extends Call { - _returnTarget.foreach(x => returnTarget = x) /* override def locals: Set[Variable] = condition match { case Some(c) => c.locals case None => Set() @@ -182,10 +167,9 @@ object DirectCall: def unapply(i: DirectCall): Option[(Procedure, Option[Block], Option[String])] = Some(i.target, i.returnTarget, i.label) class IndirectCall(var target: Variable, - private val _returnTarget: Option[Block] = None, + override val returnTarget: Option[Block] = None, override val label: Option[String] = None ) extends Call { - _returnTarget.foreach(x => returnTarget = x) /* override def locals: Set[Variable] = condition match { case Some(c) => c.locals + target case None => Set(target) From f7f633b7aebcde0917e4e49f40324700d07ba092 Mon Sep 17 00:00:00 2001 From: l-kent Date: Tue, 7 May 2024 09:18:09 +1000 Subject: [PATCH 5/7] fix issue with reassigning a block's jump --- src/main/scala/ir/Program.scala | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/scala/ir/Program.scala b/src/main/scala/ir/Program.scala index ee9635150..9f0a1a540 100644 --- a/src/main/scala/ir/Program.scala +++ b/src/main/scala/ir/Program.scala @@ -376,7 +376,8 @@ class Block private ( _fallthrough = g } - def jump_=(j: Jump): Unit = { + private def jump_=(j: Jump): Unit = { + require(!j.hasParent) if (j ne _jump) { _jump.deParent() _jump = j @@ -385,6 +386,11 @@ class Block private ( } def replaceJump(j: Jump): Block = { + if (j.hasParent) { + val parent = j.parent + j.deParent() + parent.jump = GoTo(Set.empty) + } jump = j this } From 0e429af410a129b38e10c56d21abf0603a78fee7 Mon Sep 17 00:00:00 2001 From: l-kent Date: Thu, 23 May 2024 09:10:05 +1000 Subject: [PATCH 6/7] fix intrusive list test --- src/main/scala/ir/Program.scala | 2 +- .../scala/util/intrusive_list/IntrusiveList.scala | 4 +--- .../IntrusiveListPublicInterfaceTest.scala | 15 +++------------ 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/main/scala/ir/Program.scala b/src/main/scala/ir/Program.scala index 9f0a1a540..a8337d6ed 100644 --- a/src/main/scala/ir/Program.scala +++ b/src/main/scala/ir/Program.scala @@ -359,7 +359,7 @@ class Block private ( statements.onRemove = x => x.deParent() def this(label: String, address: Option[Int] = None, statements: IterableOnce[Statement] = Set.empty, jump: Jump = GoTo(Set.empty)) = { - this(label, address, IntrusiveList.from(statements), jump, mutable.HashSet.empty, None) + this(label, address, IntrusiveList().addAll(statements), jump, mutable.HashSet.empty, None) } def jump: Jump = _jump diff --git a/src/main/scala/util/intrusive_list/IntrusiveList.scala b/src/main/scala/util/intrusive_list/IntrusiveList.scala index 22d9f6323..a6c5f0b93 100644 --- a/src/main/scala/util/intrusive_list/IntrusiveList.scala +++ b/src/main/scala/util/intrusive_list/IntrusiveList.scala @@ -356,9 +356,7 @@ final class IntrusiveList[T <: IntrusiveListElement[T]] private ( } object IntrusiveList { - def from[T <: IntrusiveListElement[T]](it: IterableOnce[T]): IntrusiveList[T] = IntrusiveList[T]().addAll(it) - - def empty[T <: IntrusiveListElement[T]]: IntrusiveList[T] = new IntrusiveList[T]() + def empty[T <: IntrusiveListElement[T]]: IntrusiveList[T] = IntrusiveList[T]() } /** diff --git a/src/test/scala/util/intrusive_list/IntrusiveListPublicInterfaceTest.scala b/src/test/scala/util/intrusive_list/IntrusiveListPublicInterfaceTest.scala index 5334181a0..f9f89867f 100644 --- a/src/test/scala/util/intrusive_list/IntrusiveListPublicInterfaceTest.scala +++ b/src/test/scala/util/intrusive_list/IntrusiveListPublicInterfaceTest.scala @@ -50,9 +50,9 @@ class IntrusiveListPublicInterfaceTest extends AnyFunSuite { // x.foreach(println(_)) - val y = x.head() + val y = x.head assert(y.t == 10) - assert(x.back().t == 14) + assert(x.back.t == 14) } test("Clear") { @@ -183,18 +183,9 @@ class IntrusiveListPublicInterfaceTest extends AnyFunSuite { } test("construct") { - val l = getSequentialList(3) - - val l2 = IntrusiveList.from(l) - assert(l2.size == 3) - - assert(l.forall(x => l2.contains(x))) - - assert (l eq l2) - val l3 = mutable.ArrayBuffer(Elem(1), Elem(2), Elem(3)) - val l4 = IntrusiveList.from(l3) + val l4 = IntrusiveList().addAll(l3) assert(l3 ne l4) assert(l3.forall(x => l4.contains(x))) From 6f3231cb8d16cccd9bb53a0c2041ee5be4304752 Mon Sep 17 00:00:00 2001 From: l-kent Date: Thu, 6 Jun 2024 09:33:16 +1000 Subject: [PATCH 7/7] test for block parent bug fix, change to DSL for clarity --- src/main/scala/ir/dsl/DSL.scala | 11 +++--- src/test/scala/LiveVarsAnalysisTests.scala | 26 ++++++------- src/test/scala/PointsToTest.scala | 6 +-- src/test/scala/ir/IRTest.scala | 44 ++++++++++++++++++++-- 4 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/main/scala/ir/dsl/DSL.scala b/src/main/scala/ir/dsl/DSL.scala index 161f0d19e..d19b362e6 100644 --- a/src/main/scala/ir/dsl/DSL.scala +++ b/src/main/scala/ir/dsl/DSL.scala @@ -47,7 +47,10 @@ case class EventuallyIndirectCall(target: Variable, fallthrough: Option[DelayNam case class EventuallyCall(target: DelayNameResolve, fallthrough: Option[DelayNameResolve]) extends EventuallyJump { override def resolve(p: Program): DirectCall = { - val t = target.resolveProc(p).get + val t = target.resolveProc(p) match { + case Some(x) => x + case None => throw Exception("can't resolve proc " + p) + } val ft = fallthrough.flatMap(_.resolveBlock(p)) DirectCall(t, ft) } @@ -70,11 +73,9 @@ def goto(targets: List[String]): EventuallyGoto = { EventuallyGoto(targets.map(p => DelayNameResolve(p))) } -def indirectCall(tgt: String, fallthrough: Option[String]): EventuallyCall = EventuallyCall(DelayNameResolve(tgt), fallthrough.map(x => DelayNameResolve(x))) +def directCall(tgt: String, fallthrough: Option[String]): EventuallyCall = EventuallyCall(DelayNameResolve(tgt), fallthrough.map(x => DelayNameResolve(x))) -def call(tgt: String, fallthrough: Option[String]): EventuallyCall = EventuallyCall(DelayNameResolve(tgt), fallthrough.map(x => DelayNameResolve(x))) - -def call(tgt: Variable, fallthrough: Option[String]): EventuallyIndirectCall = EventuallyIndirectCall(tgt, fallthrough.map(x => DelayNameResolve(x))) +def indirectCall(tgt: Variable, fallthrough: Option[String]): EventuallyIndirectCall = EventuallyIndirectCall(tgt, fallthrough.map(x => DelayNameResolve(x))) // def directcall(tgt: String) = EventuallyCall(DelayNameResolve(tgt), None) diff --git a/src/test/scala/LiveVarsAnalysisTests.scala b/src/test/scala/LiveVarsAnalysisTests.scala index e47c63679..2b3bf84c6 100644 --- a/src/test/scala/LiveVarsAnalysisTests.scala +++ b/src/test/scala/LiveVarsAnalysisTests.scala @@ -31,10 +31,10 @@ class LiveVarsAnalysisTests extends AnyFunSuite, TestUtil { block("first_call", r0ConstantAssign, r1ConstantAssign, - call("callee1", Some("second_call")) + directCall("callee1", Some("second_call")) ), block("second_call", - call("callee2", Some("returnBlock")) + directCall("callee2", Some("returnBlock")) ), block("returnBlock", ret @@ -69,10 +69,10 @@ class LiveVarsAnalysisTests extends AnyFunSuite, TestUtil { block("first_call", r0ConstantAssign, r1ConstantAssign, - call("callee1", Some("second_call")) + directCall("callee1", Some("second_call")) ), block("second_call", - call("callee2", Some("returnBlock")) + directCall("callee2", Some("returnBlock")) ), block("returnBlock", ret @@ -104,10 +104,10 @@ class LiveVarsAnalysisTests extends AnyFunSuite, TestUtil { var program = prog( proc("main", block("main_first_call", - call("wrapper1", Some("main_second_call")) + directCall("wrapper1", Some("main_second_call")) ), block("main_second_call", - call("wrapper2", Some("main_return")) + directCall("wrapper2", Some("main_return")) ), block("main_return", ret) ), @@ -117,19 +117,19 @@ class LiveVarsAnalysisTests extends AnyFunSuite, TestUtil { proc("wrapper1", block("wrapper1_first_call", LocalAssign(R1, constant1), - call("callee", Some("wrapper1_second_call")) + directCall("callee", Some("wrapper1_second_call")) ), block("wrapper1_second_call", - call("callee2", Some("wrapper1_return"))), + directCall("callee2", Some("wrapper1_return"))), block("wrapper1_return", ret) ), proc("wrapper2", block("wrapper2_first_call", LocalAssign(R2, constant1), - call("callee", Some("wrapper2_second_call")) + directCall("callee", Some("wrapper2_second_call")) ), block("wrapper2_second_call", - call("callee3", Some("wrapper2_return"))), + directCall("callee3", Some("wrapper2_return"))), block("wrapper2_return", ret) ) ) @@ -148,7 +148,7 @@ class LiveVarsAnalysisTests extends AnyFunSuite, TestUtil { var program = prog( proc("main", block("lmain", - call("killer", Some("aftercall")) + directCall("killer", Some("aftercall")) ), block("aftercall", LocalAssign(R0, R1), @@ -212,7 +212,7 @@ class LiveVarsAnalysisTests extends AnyFunSuite, TestUtil { block( "lmain", LocalAssign(R0, R1), - call("main", Some("return")) + directCall("main", Some("return")) ), block("return", LocalAssign(R0, R2), @@ -240,7 +240,7 @@ class LiveVarsAnalysisTests extends AnyFunSuite, TestUtil { ), block( "recursion", - call("main", Some("assign")) + directCall("main", Some("assign")) ), block("assign", LocalAssign(R0, R2), diff --git a/src/test/scala/PointsToTest.scala b/src/test/scala/PointsToTest.scala index afcb2d6bb..38ce1afc3 100644 --- a/src/test/scala/PointsToTest.scala +++ b/src/test/scala/PointsToTest.scala @@ -168,7 +168,7 @@ class PointsToTest extends AnyFunSuite with OneInstancePerTest with BeforeAndAft goto("0x1") ), block("0x1", - call("p2", Some("returntarget")) + directCall("p2", Some("returntarget")) ), block("returntarget", ret @@ -217,7 +217,7 @@ class PointsToTest extends AnyFunSuite with OneInstancePerTest with BeforeAndAft goto("0x1") ), block("0x1", - call("p2", Some("returntarget")) + directCall("p2", Some("returntarget")) ), block("returntarget", ret @@ -227,7 +227,7 @@ class PointsToTest extends AnyFunSuite with OneInstancePerTest with BeforeAndAft block("l_foo", LocalAssign(getRegister("R0"), MemoryLoad(mem, BinaryExpr(BVADD, getRegister("R31"), bv64(6)), LittleEndian, 64)), LocalAssign(getRegister("R1"), BinaryExpr(BVADD, getRegister("R31"), bv64(10))), - call("p2", Some("l_foo_1")) + directCall("p2", Some("l_foo_1")) ), block("l_foo_1", ret, diff --git a/src/test/scala/ir/IRTest.scala b/src/test/scala/ir/IRTest.scala index dd1e21081..5eff69ded 100644 --- a/src/test/scala/ir/IRTest.scala +++ b/src/test/scala/ir/IRTest.scala @@ -142,7 +142,7 @@ class IRTest extends AnyFunSuite { ), block("l_main_1", LocalAssign(R0, bv64(22)), - call("p2", Some("returntarget")) + directCall("p2", Some("returntarget")) ), block("returntarget", ret @@ -246,7 +246,7 @@ class IRTest extends AnyFunSuite { LocalAssign(R0, bv64(22)), LocalAssign(R0, bv64(22)), LocalAssign(R0, bv64(22)), - call("main", None) + directCall("main", None) ).resolve(p) val b2 = block("newblock1", LocalAssign(R0, bv64(22)), @@ -271,7 +271,7 @@ class IRTest extends AnyFunSuite { assert(called.incomingCalls().isEmpty) val b3 = block("newblock3", LocalAssign(R0, bv64(22)), - call("called", None) + directCall("called", None) ).resolve(p) assert(b3.calls.toSet == Set(p.procs("called"))) @@ -333,7 +333,7 @@ class IRTest extends AnyFunSuite { proc("main", block("l_main", LocalAssign(R0, bv64(10)), - call("p1", Some("returntarget")) + directCall("p1", Some("returntarget")) ), block("returntarget", ret @@ -365,5 +365,41 @@ class IRTest extends AnyFunSuite { } + test("replace jump") { + val p = prog( + proc("p1", + block("b1", + LocalAssign(R0, bv64(10)), + ret + ) + ), + proc("main", + block("l_main", + LocalAssign(R0, bv64(10)), + indirectCall(R1, Some("returntarget")) + ), + block("block2", + directCall("p1", Some("returntarget")) + ), + block("returntarget", + ret + ) + ), + ) + + val main = p.blocks("l_main") + val p1 = p.procs("p1") + val block2 = p.blocks("block2") + + val oldJump = main.jump + val newJump = block2.jump + + main.replaceJump(newJump) + + assert(newJump.parent == main) + assert(block2.jump.isInstanceOf[GoTo]) + assert(block2.jump.asInstanceOf[GoTo].targets.isEmpty) + } + }