Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added functionality to track overlapping accesses #258

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 41 additions & 10 deletions src/main/scala/analysis/data_structure_analysis/Graph.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import analysis.solvers.DSAUnionFindSolver
import analysis.evaluateExpression
import cfg_visualiser.*
import ir.*
import specification.{ExternalFunction, SymbolTableEntry}
import specification.{ExternalFunction, FuncEntry, SpecGlobal, SymbolTableEntry}

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
Expand Down Expand Up @@ -128,12 +128,30 @@ class Graph(val proc: Procedure,

// creates the globals from the symbol tables
val globalMapping = mutable.Map[AddressRange, Field]()
globals.foreach { global =>
val node = Node(Some(this), global.size)
node.allocationRegions.add(DataLocation(global.name, global.address, global.size / 8))
node.flags.global = true
node.flags.incomplete = true
globalMapping.update(AddressRange(global.address, global.address + global.size / 8), Field(node, 0))
globals.foreach {
global =>
global match
case FuncEntry(name, size, address) =>
val func = Node(Some(this), size)
func.allocationRegions.add(DataLocation(name, -address, size / 8))
func.flags.global = true
func.flags.incomplete = true
globalMapping.update(AddressRange(-address, (-address - size) / 8), Field(func, 0))

val pointer = Node(Some(this), 8)
pointer.allocationRegions.add(DataLocation(s"$name's pointer@$address", address, 8))
pointer.flags.global = true
pointer.flags.incomplete = true
pointer.cells(0).pointee = Some(Slice(func.cells(0), 0))
globalMapping.update(AddressRange(address, address + 8), Field(pointer, 0))
case SpecGlobal(name, size, arraySize, address) =>
val node = Node(Some(this), size)
node.allocationRegions.add(DataLocation(name, address, size / 8))
node.flags.global = true
node.flags.incomplete = true
globalMapping.update(AddressRange(address, address + size / 8), Field(node, 0))
case _ => ???

}

// creates a global for each relocation entry in the symbol table
Expand Down Expand Up @@ -189,6 +207,18 @@ class Graph(val proc: Procedure,
global
}

// determine if an address is a global and return the corresponding global(s) if it is.
def getGlobal(address: BigInt, size: Int): Seq[DSAGlobal] =
var global: Seq[DSAGlobal] = Seq.empty
for ((range, field) <- globalMapping) {
if (address < range.end && range.start < address + size) ||
(address + size > range.end && address < range.end) ||
(address >= range.start && (address < range.end || (range.start == range.end && range.end == address))) then
global = global ++ Seq(DSAGlobal(range, field))

}
global.sortBy(f => f.addressRange.start)

def getCells(pos: CFGPosition, arg: Variable): Set[Slice] = {
if (reachingDefs(pos).contains(arg)) {
reachingDefs(pos)(arg).map(definition => varToCell(definition)(arg))
Expand Down Expand Up @@ -283,7 +313,7 @@ class Graph(val proc: Procedure,
val offset = field.offset + find(field.node).offset
val cellOffset = node.getCell(offset).offset
val internalOffset = offset - cellOffset
arrows.append(StructArrow(DotStructElement(s"Global_${range.start}_${range.end}", None), DotStructElement(node.id.toString, Some(cellOffset.toString)), internalOffset.toString))
// arrows.append(StructArrow(DotStructElement(s"Global_${range.start}_${range.end}", None), DotStructElement(node.id.toString, Some(cellOffset.toString)), internalOffset.toString))
}

stackMapping.foreach { (offset, dsn) =>
Expand Down Expand Up @@ -541,7 +571,8 @@ class Graph(val proc: Procedure,

resultCells.keys.foreach { offset =>
val collapsedCell = resultNode.addCell(offset, resultLargestAccesses(offset))
val outgoing: Set[Slice] = cells.flatMap { (_, cell) =>
val cells = resultCells(offset)
val outgoing: Set[Slice] = cells.flatMap { cell =>
if (cell.pointee.isDefined) {
Some(cell.getPointee)
} else {
Expand Down Expand Up @@ -688,7 +719,7 @@ class Graph(val proc: Procedure,
if !idToNode.contains(field.node.id) then
val newNode = node.cloneSelf(newGraph)
idToNode.update(field.node.id, newNode)
newGraph.globalMapping.update(range, Field(idToNode(field.node.id), field.offset + offset))
newGraph.globalMapping.update(range, Field(idToNode(field.node.id), field.offset))
}

val queue = mutable.Queue[Node]()
Expand Down
176 changes: 112 additions & 64 deletions src/main/scala/analysis/data_structure_analysis/LocalPhase.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,6 @@ class LocalPhase(proc: Procedure,
val varToSym: Map[CFGPosition, Map[Variable, Set[SymbolicAddress]]] = symResults.map { (position, innerMap) =>
val newMap = innerMap.keys.foldLeft(Map[Variable, Set[SymbolicAddress]]()) { (m, access) =>
if (m.contains(access.accessor)) {
// every variable pointing to a stack region ONLY has one symbolic access associated with it.
// m(access.accessor).foreach(
// sym =>
// if (sym.symbolicBase.isInstanceOf[StackLocation]) then
// println(m)
// println(access.accessor)
// println(access)
// print("")
// //assert(!sym.symbolicBase.isInstanceOf[StackLocation])
// )
// assert(!access.symbolicBase.isInstanceOf[StackLocation])
m + (access.accessor -> (m(access.accessor) + access))
} else {
m + (access.accessor -> Set(access))
Expand All @@ -60,48 +49,71 @@ class LocalPhase(proc: Procedure,
position -> newMap
}

private def getStack(offset: BigInt): Cell = {

private def getStack(offset: BigInt, size: Int): Cell = {
var last: BigInt = 0
if graph.stackMapping.contains(offset) then
graph.stackMapping(offset).cells(0)
else
breakable {
graph.stackMapping.keys.foreach {
elementOffset =>
if offset < elementOffset then
break
else
last = elementOffset
var headNodeOffset: BigInt = -1

val head: Cell =
if graph.stackMapping.contains(offset) then
headNodeOffset = 0
graph.stackMapping(offset).cells(0)
else
breakable {
graph.stackMapping.keys.toSeq.sorted.foreach(
elementOffset =>
if offset < elementOffset then
break
else
last = elementOffset
)
}
}
val diff = offset - last
assert(graph.stackMapping.contains(last))
graph.stackMapping(last).getCell(diff)
val diff = offset - last
headNodeOffset = offset
assert(graph.stackMapping.contains(last))
graph.stackMapping(last).getCell(diff)

// DSA grows cell size with size
// selfCollapse at the end to merge all the overlapping accessed size
// However, the above approach prevents distinct multi loads
// graph.find(head).growSize(size)
val headOffset = last + head.offset
graph.stackMapping.keys.toSeq.filter(off => off > headOffset && off < headOffset + size).sorted.foreach {
off =>
val stackDiff = off - headOffset
val updatedHead = graph.find(head)
val newHeadOffset = updatedHead.offset
val headNode = updatedHead.node.get
graph.mergeCells(headNode.addCell(newHeadOffset + stackDiff, 0), graph.find(graph.stackMapping(off).cells(0)))
}
// graph.selfCollapse(head.node.get)
head
}


/**
* if an expr is the address of a stack location return its corresponding cell
* @param pos IL position where the expression is used
*/
private def isStack(expr: Expr, pos: CFGPosition): Option[Cell] = {
private def isStack(expr: Expr, pos: CFGPosition, size : Int = 0): Option[Cell] = {
expr match
case BinaryExpr(_, arg1: Variable, arg2) if varToSym.contains(pos) && varToSym(pos).contains(arg1) &&
case BinaryExpr(op, arg1: Variable, arg2) if varToSym.contains(pos) && varToSym(pos).contains(arg1) &&
varToSym(pos)(arg1).exists(s => s.symbolicBase.isInstanceOf[StackLocation]) =>
evaluateExpression(arg2, constProp(pos)) match
case Some(v) =>
val stackRegions = varToSym(pos)(arg1).filter(s => s.symbolicBase.isInstanceOf[StackLocation])
val res = stackRegions.tail.foldLeft(getStack(v.value + stackRegions.head.offset)) {
val res = stackRegions.tail.foldLeft(getStack(v.value + stackRegions.head.offset, size)) {
(res, sym) =>
graph.mergeCells(res, getStack(v.value + sym.offset))
graph.mergeCells(res, getStack(v.value + sym.offset, size))
}
Some(res)
case None => None
case arg: Variable if varToSym.contains(pos) && varToSym(pos).contains(arg) &&
varToSym(pos)(arg).exists(s => s.symbolicBase.isInstanceOf[StackLocation]) =>
val stackRegions = varToSym(pos)(arg).filter(s => s.symbolicBase.isInstanceOf[StackLocation])
val res = stackRegions.tail.foldLeft(getStack(stackRegions.head.offset)) {
val res = stackRegions.tail.foldLeft(getStack(stackRegions.head.offset, size)) {
(res, sym) =>
graph.mergeCells(res, getStack(sym.offset))
graph.mergeCells(res, getStack(sym.offset, size))
}
Some(res)
case _ => None
Expand All @@ -120,22 +132,37 @@ class LocalPhase(proc: Procedure,
* if an expr is the address of a global location return its corresponding cell
* @param pos IL position where the expression is used
*/
def isGlobal(expr: Expr, pos: CFGPosition, size: Int = 0): Option[Cell] = {
def getGlobal(expr: Expr, pos: CFGPosition, size: Int = 0): Option[Cell] = {
val value = evaluateExpression(expr, constProp(pos))
if value.isDefined then
val global = graph.isGlobal(value.get.value)
if global.isDefined then
val address = value.get.value
val DSAGlobal(range: AddressRange, Field(node, internal)) = global.get
val offset = address - range.start
node.addCell(internal + offset, size)
graph.selfCollapse(node)
if node.collapsed then
Some(node.cells(0))
else
Some(node.getCell(internal + offset))
else
None
if value.isDefined then
getGlobal(value.get.value, size)
else
None
}

def getGlobal(address: BigInt, size: Int): Option[Cell] = {
val globals = graph.getGlobal(address, size)
if globals.nonEmpty then
val head = globals.head
val DSAGlobal(range: AddressRange, Field(node, internal)) = head
val headOffset: BigInt = if address > range.start then address - range.start + internal else internal
val headNode = node
val headCell: Cell = node.addCell(headOffset, 0) // DSA has the size of the added cell should as size with
// selfCollapse at the end to merge all the overlapping accessed size
// However, the above approach prevent distinct multi loads
// graph.selfCollapse(headNode)
val tail = globals.tail
tail.foreach {
g =>
val DSAGlobal(range: AddressRange, Field(node, internal)) = g
val offset: BigInt = if address > range.start then address - range.start + internal else internal
node.addCell(offset, 0)
graph.selfCollapse(node)
assert(range.start >= address)
graph.mergeCells(graph.find(headNode.addCell(range.start - address, 0)), graph.find(node.getCell(offset)))
}
graph.selfCollapse(graph.find(headCell).node.get)
Some(graph.find(headCell))
else
None
}
Expand Down Expand Up @@ -220,6 +247,25 @@ class LocalPhase(proc: Procedure,
node.cells(0)
}



def multiAccess(lhsOrValue: Cell, pointer: Cell, size: Int): Unit = {
// TODO there should be another check here to see we cover the bytesize
// otherwise can fall back on expanding

val diff = pointer.offset - lhsOrValue.offset
val startPointerOffset = pointer.offset
val lhsNode = lhsOrValue.node.get


val pointers = pointer.node.get.cells.filter((offset, _) => offset >= startPointerOffset && offset < startPointerOffset + size).toSeq.sortBy((offset, cell) => offset)
for ((offset, cell) <- pointers) {
val lhs = lhsNode.addCell(offset - diff, 0) // todo check if 0 is the right size
graph.mergeCells(lhs, graph.adjust(graph.find(cell).getPointee))
}
}


def visit(n: CFGPosition): Unit = {
if visited.contains(n) then
return
Expand Down Expand Up @@ -248,7 +294,7 @@ class LocalPhase(proc: Procedure,
case Assign(variable, rhs, _) =>
val expr: Expr = unwrapPaddingAndSlicing(rhs)
val lhsCell = graph.adjust(graph.varToCell(n)(variable))
var global = isGlobal(rhs, n)
var global = getGlobal(rhs, n)
var stack = isStack(rhs, n)
if global.isDefined then // Rx = global address
graph.mergeCells(lhsCell, global.get)
Expand Down Expand Up @@ -276,12 +322,12 @@ class LocalPhase(proc: Procedure,
assert(size % 8 == 0)
val byteSize = size/8
lhsCell.node.get.flags.read = true
global = isGlobal(index, n, byteSize)
stack = isStack(index, n)
global = getGlobal(index, n, byteSize)
stack = isStack(index, n, byteSize)
if global.isDefined then
graph.mergeCells(lhsCell,graph.adjust(graph.find(global.get).getPointee))
multiAccess(lhsCell, graph.find(global.get), byteSize)
else if stack.isDefined then
graph.mergeCells(lhsCell, graph.adjust(graph.find(stack.get).getPointee))
multiAccess(lhsCell, graph.find(stack.get), byteSize)
else
index match
case BinaryExpr(op, arg1: Variable, arg2) if op.equals(BVADD) =>
Expand Down Expand Up @@ -311,14 +357,20 @@ class LocalPhase(proc: Procedure,
reachingDefs(n)(value).foreach(visit)
assert(size % 8 == 0)
val byteSize = size / 8
val global = isGlobal(index, n, byteSize)
val global = getGlobal(index, n)
val stack = isStack(index, n)
val addressPointee: Cell =
if global.isDefined then
graph.adjust(graph.find(global.get).getPointee)
else if stack.isDefined then
graph.adjust(graph.find(stack.get).getPointee)
else

val valueCells = graph.getCells(n, value)
val valueCell = valueCells.tail.foldLeft(graph.adjust(valueCells.head)) { (c, slice) =>
graph.mergeCells(graph.adjust(slice), c)
}

if global.isDefined then
multiAccess(valueCell, graph.find(global.get), byteSize)
else if stack.isDefined then
multiAccess(valueCell, graph.find(stack.get), byteSize)
else
val addressPointee: Cell =
index match
case BinaryExpr(op, arg1: Variable, arg2) if op.equals(BVADD) =>
evaluateExpression(arg2, constProp(n)) match
Expand All @@ -337,11 +389,7 @@ class LocalPhase(proc: Procedure,
case _ =>
???

addressPointee.node.get.flags.modified = true
val valueCells = graph.getCells(n, value)
val result = valueCells.foldLeft(addressPointee) { (c, slice) =>
graph.mergeCells(graph.adjust(slice), c)
}
graph.mergeCells(valueCell, addressPointee)
case _ => // if value is a literal ignore it
}
case _ =>
Expand Down
Loading