diff options
| author | iximeow <me@iximeow.net> | 2015-03-02 15:34:34 -0800 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2015-03-02 15:34:34 -0800 | 
| commit | 9827904a6aa6b649665cf78fa56716011fb37e6d (patch) | |
| tree | a7d7ef6c08fa92226bee434f5e6d29d179e80c21 /src/Instruction.scala | |
initial commit
Diffstat (limited to 'src/Instruction.scala')
| -rw-r--r-- | src/Instruction.scala | 306 | 
1 files changed, 306 insertions, 0 deletions
| diff --git a/src/Instruction.scala b/src/Instruction.scala new file mode 100644 index 0000000..7177b89 --- /dev/null +++ b/src/Instruction.scala @@ -0,0 +1,306 @@ +package ixee.re.disasm + +import ixee.cryptopals.utils.ByteUtils._ +import ixee.cryptopals.utils.FunctionUtils._ + +import scala.collection.mutable.Map + +case class Source(value: Int) +case class Destination(value: Int) + +sealed trait AddressingMode { +  def modeName: String +  override def toString: String = modeName +  def nameifyRegister(reg: Int): String = reg match { +    case 0 => "pc" +    case 1 => "sp" +    case 2 => "sr" +    case 3 => "cg" +    case num @ _ => s"r$num" +  } +  def stringifyWith(reg: Int): String +} + +sealed trait OneOpAddressing extends AddressingMode +sealed trait TwoOpAddressing extends AddressingMode +sealed trait TwoOpSourceAddressing extends TwoOpAddressing +sealed trait TwoOpDestAddressing extends TwoOpAddressing + +object TwoOpSourceAddressingModes { +  // just alias the apply over to make names look right at call sites. +  // think hard about refactoring this +  def apply(register: Int, mode: Int): Option[TwoOpSourceAddressing] = OneOpAddressingModes(register, mode) +} + +object OneOpAddressingModes { +  case class AddressingMode(as: Int, name: String, stringifier: String => String) extends OneOpAddressing with TwoOpSourceAddressing { +    def modeName = name +    def stringifyWith(reg: Int): String = stringifier(nameifyRegister(reg)) +  } + +  def apply(register: Int, mode: Int): Option[AddressingMode] = register match { +    case 0 => PCModes(mode) orElse General(mode) +    case 2 => SRModes(mode) orElse General(mode) +    case 3 => CGModes(mode) orElse General(mode) +    case _ => General(mode) +  } + +  trait Modes { +    private val modeMap: Map[Int, AddressingMode] = Map() +    def Mode(as: Int, name: String, stringifier: String => String) = AddressingMode(as, name, stringifier).tap(modeMap += as -> _) + +    def apply(x: Int): Option[AddressingMode] = modeMap.get(x) +  } + +  object PCModes extends Modes { +    Mode(3, "NextWord", reg => s"@$reg+ (next word)") +  } +  object SRModes extends Modes { +    Mode(2, "Const4", reg => "#4") +    Mode(3, "Const8", reg => "#8") +  } +  object CGModes extends Modes { +    Mode(0, "Const0", reg => "#0") +    Mode(1, "Const1", reg => "#1") +    Mode(2, "Const2", reg => "#2") +    Mode(3, "ConstNeg1", reg => "#-1") +  } +  object General extends Modes { +    Mode(0, "RegisterDirect", ident) +    Mode(1, "Indexed", reg => s"@PC+($reg)") +    Mode(2, "RegisterIndirect", reg => s"@$reg") +    Mode(3, "IndirectAutoInc", reg => s"@$reg+") +  } + +  PCModes +  SRModes +  CGModes +  General +} + + +object TwoOpDestAddressingModes { +  case class AddressingMode(as: Int, name: String, stringifier: String => String) extends TwoOpDestAddressing { +    def modeName = name +    def stringifyWith(reg: Int): String = stringifier(nameifyRegister(reg)) +  } + +  def apply(register: Int, mode: Int): Option[AddressingMode] = register match { +    case 0 => PCModes(mode) orElse General(mode) +    case 2 => SRModes(mode) orElse General(mode) +    case _ => General(mode) +  } + +  trait Modes { +    private val modeMap: Map[Int, AddressingMode] = Map() +    def Mode(as: Int, name: String, stringifier: String => String) = AddressingMode(as, name, stringifier).tap(modeMap += as -> _) + +    def apply(x: Int): Option[AddressingMode] = modeMap.get(x) +  } + +  object PCModes extends Modes { +    Mode(1, "Symbolic", reg => s"<??> (symbolic? x(PC)?") +  } +  object SRModes extends Modes { +    Mode(1, "Absolute", reg => s"&@PC+ (value at nextWord)") +  } +  object General extends Modes { +    Mode(0, "RegisterDirect", reg => s"$reg") +    Mode(1, "Indexed", reg => s"@PC+($reg)") +  } + +  PCModes +  SRModes +  General +} + +sealed trait OpCode { +  def instrName: String +  override def toString: String = instrName +} + +sealed trait NoOpCode extends OpCode +sealed trait OneOpCode extends OpCode +sealed trait TwoOpCode extends OpCode + +object Opcodes { +  def opcodes: Map[Int, OpCode] = noOpCodes ++ oneOpCodes ++ twoOpCodes +  val noOpCodes: Map[Int, NoOpCode] = Map() +  val oneOpCodes: Map[Int, OneOpCode] = Map() +  val twoOpCodes: Map[Int, TwoOpCode] = Map() + +  def apply(value: Int) = opcodes.get(value) +  def noOp(value: Int) = noOpCodes.get(value) +  def oneOp(value: Int) = oneOpCodes.get(value) +  def twoOp(value: Int) = twoOpCodes.get(value) + +  object NoOpCodes { +    val Prefix = 0x01 +    case class Code(value: Byte, name: String) extends NoOpCode { def instrName = name } +    object Code { +      def apply(value: Int, name: String) = new Code(value.toByte, name).tap(code => noOpCodes += ((((Prefix << 3) + value) << 10) -> code)) +    } + +    Code(0x00, "JNE") +    Code(0x01, "JEQ") +    Code(0x02, "JNC") +    Code(0x03, "JC ") +    Code(0x04, "JN ") +    Code(0x05, "JGE") +    Code(0x06, "JL ") +    Code(0x07, "JMP") +  } + +  object OneOpCodes { +    val Prefix = 0x04 +    case class Code(value: Byte, name: String) extends OneOpCode { def instrName = name } +    object Code { +      def apply(value: Int, name: String) = new Code(value.toByte, name).tap(code => oneOpCodes += ((((Prefix << 3) + value) << 7) -> code)) +    } + +    Code(0x00, "RRC") +    Code(0x01, "SWPB") +    Code(0x02, "RRA") +    Code(0x03, "SXT") +    Code(0x04, "PUSH") +    Code(0x05, "CALL") +    Code(0x06, "RETI") +//    Code(0x07, "NotImplemented") +  } + +  object TwoOpCodes { +    val Prefix = 0x1 +    case class Code(value: Byte, name: String) extends TwoOpCode { def instrName = name } +    object Code { +      def apply(value: Int, name: String) = new Code(value.toByte, name).tap(code => twoOpCodes += ((value @<< 12) -> code)) +    } + +    Code(0x04, "MOV") +    Code(0x05, "ADD") +    Code(0x06, "ADDC") +    Code(0x07, "SUBC") +    Code(0x08, "SUB") +    Code(0x09, "CMP") +    Code(0x0a, "DADD") +    Code(0x0b, "BIT") +    Code(0x0c, "BIC") +    Code(0x0d, "BIS") +    Code(0x0e, "XOR") +    Code(0x0f, "AND") +  } + +  // forces the various opcode bodies to be evaluated. kinda weird, but it works so welp. +  NoOpCodes +  OneOpCodes +  TwoOpCodes +} + +sealed trait Instruction + +case class NoOpInst(code: NoOpCode, offset: Int) extends Instruction { +  override def toString: String = { +    s"$code -> $offset" +  } +} +case class OneOpInst(code: OneOpCode, byte: Boolean, dest: Int, addressMode: OneOpAddressing) extends Instruction { +  override def toString: String = { +    val byteStr = if (byte) ".B" else "  " +    s"$code$byteStr ${addressMode.stringifyWith(dest)}" +  } +} +case class TwoOpInst(code: TwoOpCode, byte: Boolean, src: Int, srcMode: TwoOpSourceAddressing, dest: Int, dstMode: TwoOpDestAddressing) extends Instruction { +  override def toString: String = { +    val byteStr = if (byte) ".B" else "  " +    s"$code$byteStr ${srcMode.stringifyWith(src)}, ${dstMode.stringifyWith(dest)}" +  } +} + +object NoOp { +  def info(bytes: (Byte, Byte)): (Int, Int) = { +    val op = (bytes._1 & 0xfc) >> 2 +    val offset = ((bytes._1 & 0x03) << 8) | bytes._2 +    (op, offset) +  } + +  def apply(bytes: (Byte, Byte)): Option[NoOpInst] = { +    val (opVal, offset) = info(bytes) +    for { +      opcode <- Opcodes.noOp(opVal << 10) +    } yield NoOpInst(opcode, offset) +  } +} + +object OneOp { +  def info(bytes: (Byte, Byte)): (Int, Int, Int, Int) = { +    val dest = (bytes._2 & 0x0f) +    val destMode = ((bytes._2 & 0x30) >> 4) +    val byteBit = ((bytes._2 & 0x40) >> 6) +    val opcode = ((bytes._1 & 0xff) << 1) | ((bytes._2 & 0x80) >> 7) +    (opcode, byteBit, dest, destMode) +  } + +  def apply(bytes: (Byte, Byte)): Option[OneOpInst] = { +    val (opVal, byteInstr, dest, rawDestMode) = info(bytes) +    for { +      opcode <- Opcodes.oneOp(opVal << 7) +      isByteOp = if (byteInstr == 1) true else false +      destMode <- OneOpAddressingModes(dest, rawDestMode) +    } yield OneOpInst(opcode, isByteOp, dest, destMode) +  } +} + +object TwoOp { +  def info(bytes: (Byte, Byte)): (Int, Int, Int, Int, Int, Int) = { +    val dest = (bytes._2 & 0x0f) +    val sourceMode = (bytes._2 & 0x30) >> 4 +    val byteBit = (bytes._2 & 0x40) >> 6 +    val destMode = (bytes._2 & 0x80) >> 7 +    val source = (bytes._1 & 0x0f) +    val opcode = (bytes._1 & 0xf0) >> 4 +    (opcode, byteBit, source, destMode, dest, sourceMode) +  } + +  def apply(bytes: (Byte, Byte)): Option[TwoOpInst] = { +    val (opVal, byteInstr, source, rawDestMode, dest, rawSourceMode) = info(bytes) + +    for { +      opcode <- Opcodes.twoOp(opVal << 12) +      isByteOp = if (byteInstr == 1) true else false +      destMode <- TwoOpDestAddressingModes(dest, rawDestMode) +      sourceMode <- TwoOpSourceAddressingModes(source, rawSourceMode) +    } yield TwoOpInst(opcode, isByteOp, source, sourceMode, dest, destMode) +  } +} + +object Instruction { +  def apply(instruction: (Byte, Byte)): Option[Instruction] = NoOp(instruction) orElse OneOp(instruction) orElse TwoOp(instruction) +  def littleEndian(instruction: String): Option[Instruction] = { +    val instr = Integer.parseInt(instruction, 16) +    val hi = (instr & 0xff00) >> 8 +    val lo = instr & 0x00ff +    apply((hi.toByte, lo.toByte)) +  } +  def apply(instruction: String): Option[Instruction] = { +    val instr = Integer.parseInt(instruction, 16) +    val hi = (instr & 0xff00) >> 8 +    val lo = instr & 0x00ff +    apply((lo.toByte, hi.toByte)) +  } + +  def noOp(instruction: (Byte, Byte)): Option[NoOpInst] = NoOp.apply(instruction) + +  def oneOp(instruction: (Byte, Byte)): Option[OneOpInst] = OneOp.apply(instruction) + +  def twoOp(instruction: (Byte, Byte)): Option[TwoOpInst] = TwoOp.apply(instruction) + +  def isNoOp(instruction: (Byte ,Byte)) = noOp(instruction).isDefined + +  def isOneOp(instruction: (Byte, Byte)) = oneOp(instruction).isDefined + +  def isTwoOp(instruction: (Byte, Byte)) = twoOp(instruction).isDefined +} + +sealed trait ByteOp { +  override def toString = s"(Single Byte: ${super.toString})" +} + | 
