<commit_before>package io.joern.ghidra2cpg.passes.mips

import ghidra.app.decompiler.DecompInterface
import ghidra.program.model.address.GenericAddress
import ghidra.program.model.lang.Register
import ghidra.program.model.listing.{Function, Instruction, Program}
import ghidra.program.model.scalar.Scalar
import ghidra.util.task.ConsoleTaskMonitor
import io.joern.ghidra2cpg.Types
import io.joern.ghidra2cpg.passes.FunctionPass
import io.joern.ghidra2cpg.processors.MipsProcessor
import io.joern.ghidra2cpg.utils.Nodes._
import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.codepropertygraph.generated.nodes.CfgNodeNew
import io.shiftleft.codepropertygraph.generated.{EdgeTypes, nodes}
import io.shiftleft.passes.{DiffGraph, IntervalKeyPool}

import scala.jdk.CollectionConverters._
import scala.language.implicitConversions

class MipsFunctionPass(currentProgram: Program,
                       filename: String,
                       function: Function,
                       cpg: Cpg,
                       keyPool: IntervalKeyPool,
                       decompInterface: DecompInterface)
    extends FunctionPass(new MipsProcessor, currentProgram, filename, function, cpg, keyPool, decompInterface) {

  val mipsCallInstructions = List("jalr", "jal")
  // Iterating over operands and add edges to call
  override def handleArguments(
      instruction: Instruction,
      callNode: CfgNodeNew
  ): Unit = {
    val mnemonicString = instruction.getMnemonicString
    if (mipsCallInstructions.contains(mnemonicString)) {
      val mipsPrefix = "^t9=>".r
      val calledFunction =
        mipsPrefix.replaceFirstIn(codeUnitFormat.getOperandRepresentationString(instruction, 0), "")
      functions.find(function => function.getName().equals(calledFunction)).foreach { callee =>
        // Array of tuples containing (checked parameter name, parameter index, parameter data type)
        var checkedParameters: Array[(String, Int, String)] = Array.empty

        if (callee.isThunk) {
          // thunk functions contain parameters already
          checkedParameters = callee.getParameters.map { parameter =>
            // checked parameter name, parameter index, parameter data type
            (Option(parameter.getName).getOrElse(parameter.getRegister.getName),
             parameter.getOrdinal + 1,
             parameter.getDataType.getName)<commit_msg>Hotfix: Parameter and literal handling for MIPS (#712)<commit_after>package io.joern.ghidra2cpg.passes.mips

import ghidra.app.decompiler.DecompInterface
import ghidra.program.model.address.GenericAddress
import ghidra.program.model.lang.Register
import ghidra.program.model.listing.{Function, Instruction, Program}
import ghidra.program.model.scalar.Scalar
import ghidra.program.util.DefinedDataIterator
import ghidra.util.task.ConsoleTaskMonitor
import io.joern.ghidra2cpg.Types
import io.joern.ghidra2cpg.passes.FunctionPass
import io.joern.ghidra2cpg.processors.MipsProcessor
import io.joern.ghidra2cpg.utils.Nodes._
import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.codepropertygraph.generated.nodes.CfgNodeNew
import io.shiftleft.codepropertygraph.generated.{EdgeTypes, nodes}
import io.shiftleft.passes.{DiffGraph, IntervalKeyPool}

import scala.jdk.CollectionConverters._
import scala.language.implicitConversions

class MipsFunctionPass(currentProgram: Program,
                       filename: String,
                       function: Function,
                       cpg: Cpg,
                       keyPool: IntervalKeyPool,
                       decompInterface: DecompInterface)
    extends FunctionPass(new MipsProcessor, currentProgram, filename, function, cpg, keyPool, decompInterface) {
  protected def findStringAtOffset(offset: Long) = {
    DefinedDataIterator
      .definedStrings(currentProgram)
      .iterator()
      .asScala
      .filter(x => x.getAddress().getOffset == offset)
      .toList
      .map(x => x.getValue.toString)
      .headOption
  }
  val mipsCallInstructions = List("jalr", "jal")
  // Iterating over operands and add edges to call
  override def handleArguments(
      instruction: Instruction,
      callNode: CfgNodeNew
  ): Unit = {
    val mnemonicString = instruction.getMnemonicString
    if (mipsCallInstructions.contains(mnemonicString)) {
      val mipsPrefix = "^t9=>".r
      val calledFunction =
        mipsPrefix.replaceFirstIn(codeUnitFormat.getOperandRepresentationString(instruction, 0), "")
      functions.find(function => function.getName().equals(calledFunction)).foreach { callee =>
        // Array of tuples containing (checked parameter name, parameter index, parameter data type)
        var checkedParameters: Array[(String, Int, String)] = Array.empty

        val instructionPcodes = highFunction
          .getPcodeOps(instruction.getPcode.toList.last.getSeqnum.getTarget)
          .asScala
          .toList
          .head
          .getInputs
          .drop(1)
        if (instructionPcodes.nonEmpty) {
          instructionPcodes.zipWithIndex foreach {
            case (input, index) =>
              if (input.isRegister) {
                val name = currentProgram.getRegister(input.getAddress).getName
                val node = createIdentifier(name,
                                            name,
                                            index,
                                            Types.registerType(name),
                                            instruction.getMinAddress.getOffsetAsBigInteger.intValue)
                addArgumentEdge(callNode, node)
              } else if (input.isConstant) {
                val node = nodes
                  .NewLiteral()
                  .code(input.getWordOffset.toHexString)
                  .order(index)
                  .argumentIndex(index)
                  .typeFullName(input.getWordOffset.toHexString)
                addArgumentEdge(callNode, node)
              } else if (input.isUnique) {
                val value = findStringAtOffset(input.getDef.getInputs.toList.head.getAddress.getOffset + 8)
                  .getOrElse(findStringAtOffset(input.getDef.getInputs.toList.head.getAddress.getOffset)
                    .getOrElse(input.getDef.getInputs.toList.head.getAddress.getOffset))
                val node = nodes
                  .NewLiteral()
                  .code(value.toString)
                  .order(index)
                  .argumentIndex(index)
                  .typeFullName(input.getWordOffset.toHexString)
                addArgumentEdge(callNode, node)
              } else {
                val node = nodes
                  .NewLiteral()
                  .code(input.toString)
                  .order(index)
                  .argumentIndex(index)
                  .typeFullName(input.toString)
                addArgumentEdge(callNode, node)
              }
          }
        }
        if (callee.isThunk) {
          // thunk functions contain parameters already
          checkedParameters = callee.getParameters.map { parameter =>
            // checked parameter name, parameter index, parameter data type
            (Option(parameter.getName).getOrElse(parameter.getRegister.getName),
             parameter.getOrdinal + 1,
             parameter.getDataType.getName)
{'fraction_non_alphanumeric': 0.08390646492434663, 'fraction_numerical': 0.0028885832187070153, 'mean_word_length': 2.4248704663212437, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '988617', 'n_tokens_mistral': 1955, 'n_tokens_neox': 1910, 'n_words': 366}