/* * TraceReplayState.java - This file is part of the Jakstab project. * Copyright 2007-2015 Johannes Kinder <jk@jakstab.org> * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, see <http://www.gnu.org/licenses/>. */ package org.jakstab.analysis.tracereplay; import java.util.Set; import org.jakstab.analysis.AbstractState; import org.jakstab.analysis.LatticeElement; import org.jakstab.analysis.UnderApproximateState; import org.jakstab.asm.AbsoluteAddress; import org.jakstab.cfa.Location; import org.jakstab.rtl.expressions.ExpressionFactory; import org.jakstab.rtl.expressions.RTLExpression; import org.jakstab.rtl.expressions.RTLNumber; import org.jakstab.util.FastSet; import org.jakstab.util.Logger; import org.jakstab.util.Tuple; import com.google.common.collect.SetMultimap; /** * States corresponding to a line number within a pre-recorded trace. Each state * stores a reference to the trace to allow direct access to recorded PC values. */ public class TraceReplayState implements UnderApproximateState { @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(TraceReplayState.class); public static TraceReplayState BOT = new TraceReplayState(); private final AbsoluteAddress cur; private final SetMultimap<AbsoluteAddress,AbsoluteAddress> succ; private TraceReplayState() { super(); cur = new AbsoluteAddress(0xF0000B07L); succ = null; } public TraceReplayState(SetMultimap<AbsoluteAddress,AbsoluteAddress> succ, AbsoluteAddress cur) { this.succ = succ; this.cur = cur; } @Override public String getIdentifier() { return cur.toString(); } @Override public Location getLocation() { throw new UnsupportedOperationException(); } /** * Get the value of the program counter at the current state. * * @return an AbsoluteAddress corresponding to the PC value for the analyzed module. */ public AbsoluteAddress getCurrentPC() { return cur; } /** * Get the value of the program counter at the current state's successor state. * * @return an AbsoluteAddress corresponding to the next PC value for the analyzed module. */ public Set<AbsoluteAddress> getNextPC() { return succ.get(cur); } @Override public AbstractState join(LatticeElement l) { throw new UnsupportedOperationException(); } @Override public Set<Tuple<RTLNumber>> projectionFromConcretization(RTLExpression... expressions) { // Only concretize expression requests from transformerFactory // Warning: If this method is invoked with 2 parameters for other reasons, it will // likely fail! if (expressions.length != 2) return null; // If not on trace, don't concretize if (isBot()) return null; RTLExpression condition = expressions[0]; RTLExpression target = expressions[1]; RTLNumber cCondition; RTLNumber cTarget; Set<Tuple<RTLNumber>> res = new FastSet<Tuple<RTLNumber>>(); for (AbsoluteAddress successor : getNextPC()) { RTLNumber nextPC = successor.toNumericConstant(); if (target instanceof RTLNumber) { // If target is a number, this is a direct jump, and maybe conditional cTarget = (RTLNumber)target; if (condition instanceof RTLNumber) { // Direct, unconditional jump cCondition = (RTLNumber)condition; } else if (target.equals(nextPC)) { // Conditional jump that is taken according to the trace cCondition = ExpressionFactory.TRUE; } else { // Conditional jump that is not taken cCondition = ExpressionFactory.FALSE; } } else { // Target is not a number, so this is an indirect jump assert (condition instanceof RTLNumber) : "There should be no conditional indirect jumps in x86!"; cCondition = (RTLNumber)condition; cTarget = nextPC; } res.add(Tuple.create(cCondition, cTarget)); } return res; } @Override public boolean isBot() { return this == BOT; } @Override public boolean isTop() { return false; } @Override public int hashCode() { return cur.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; return cur.equals(((TraceReplayState)obj).cur); } @Override public boolean lessOrEqual(LatticeElement l) { TraceReplayState other = (TraceReplayState)l; if (other.isTop() || this.isBot()) return true; return this.equals(l); } public String toString() { if (isBot()) return "Trace@BOT"; return "Trace@" + getCurrentPC() + ": Next: " + getNextPC(); } }