Example #1
0
uint32_t
findFunctionEnd(uint32_t start)
{
   static const uint32_t MaxScannedBytes = 0x400u;
   auto fnStart = start;
   auto fnMax = start;
   auto fnEnd = uint32_t { 0xFFFFFFFFu };

   for (auto addr = start; addr < start + MaxScannedBytes; addr += 4) {
      auto instr = mem::read<espresso::Instruction>(addr);
      auto data = espresso::decodeInstruction(instr);

      if (!data) {
         // If we can't decode this instruction, then we gone done f****d up
         break;
      }

      if (addr > fnMax) {
         fnMax = addr;
      }

      if (isBranchInstr(data)) {
         auto meta = getBranchMeta(addr, instr, data, nullptr);

         // Ignore call instructions
         if (!meta.isCall) {
            if (meta.isVariable) {
               // We hit a variable non-call instruction, we can't scan
               //  any further than this.  If we don't have any instructions
               //  further down, this is the final.
               if (fnMax > addr) {
                  addr = fnMax;
                  continue;
               } else {
                  fnEnd = fnMax + 4;
                  break;
               }
            } else {
               if (addr == fnMax && !meta.isConditional) {
                  if (meta.target >= fnStart && meta.target < addr) {
                     // If we are the last instruction, and this instruction unconditionally
                     //   branches backwards, that means that we must be at the end of the func.
                     fnEnd = fnMax + 4;
                     break;
                  }
               }

               // We cannot follow unconditional branches outside of the function body
               //  that we have already determined, this is because we don't want to follow
               //  tail calls!
               if (meta.target > fnMax && meta.isConditional) {
                  fnMax = meta.target;
               }
            }
         }
      }
   }

   return fnEnd;
}
Example #2
0
void
analyse(uint32_t start,
        uint32_t end)
{
   auto testStart = 0x025B81F4u;
   auto testEnd = 0x25B8374u + 4;

   // Scan through all our symbols and mark them as functions.
   // We do this first as they will not receive names if they are
   //  detected by the analysis pass due to its naming system.
   kernel::loader::lockLoader();
   const auto &modules = kernel::loader::getLoadedModules();

   for (auto &mod : modules) {
      auto codeRangeStart = 0u;
      auto codeRangeEnd = 0u;

      for (auto &sec : mod.second->sections) {
         if (sec.name.compare(".text") == 0) {
            codeRangeStart = sec.start;
            codeRangeEnd = sec.end;
            break;
         }
      }

      for (auto &sym : mod.second->symbols) {
         if (sym.second.type == kernel::loader::SymbolType::Function) {
            if (sym.second.address >= codeRangeStart && sym.second.address < codeRangeEnd) {
               markAsFunction(sym.second.address, sym.first);
            }
         }
      }
   }

   kernel::loader::unlockLoader();

   for (auto addr = start; addr < end; addr += 4) {
      auto instr = mem::read<espresso::Instruction>(addr);
      auto data = espresso::decodeInstruction(instr);

      if (!data) {
         continue;
      }

      if (isBranchInstr(data)) {
         auto meta = getBranchMeta(addr, instr, data, nullptr);

         if (!meta.isCall && !meta.isVariable) {
            sInstrData[meta.target].sourceBranches.push_back(addr);
         }

         // If this is a call, and its not variable, we should mark
         //  the target as a function, since it likely is...
         if (meta.isCall && !meta.isVariable) {
            markAsFunction(meta.target);
         }
      }
   }
}
Example #3
0
static int
cop1Emulate(int xcptno, struct pt_regs *xcp,
	    struct mips_fpu_soft_struct *ctx)
{
	mips_instruction ir;
	vaddr_t emulpc;
	vaddr_t contpc;
	unsigned int cond;
	int err = 0;


	ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err);
	if (err) {
		fpuemuprivate.stats.errors++;
		return SIGBUS;
	}

	/* XXX NEC Vr54xx bug workaround */
	if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
		xcp->cp0_cause &= ~CAUSEF_BD;

	if (xcp->cp0_cause & CAUSEF_BD) {
		/*
		 * The instruction to be emulated is in a branch delay slot
		 * which means that we have to  emulate the branch instruction
		 * BEFORE we do the cop1 instruction. 
		 *
		 * This branch could be a COP1 branch, but in that case we
		 * would have had a trap for that instruction, and would not
		 * come through this route.
		 *
		 * Linux MIPS branch emulator operates on context, updating the
		 * cp0_epc.
		 */
		emulpc = REG_TO_VA(xcp->cp0_epc + 4);	/* Snapshot emulation target */

		if (__compute_return_epc(xcp)) {
#ifdef CP1DBG
			printk("failed to emulate branch at %p\n",
				    REG_TO_VA(xcp->cp0_epc));
#endif
			return SIGILL;;
		}
		ir = mips_get_word(xcp, emulpc, &err);
		if (err) {
			fpuemuprivate.stats.errors++;
			return SIGBUS;
		}
		contpc = REG_TO_VA xcp->cp0_epc;
	} else {
		emulpc = REG_TO_VA xcp->cp0_epc;
		contpc = REG_TO_VA xcp->cp0_epc + 4;
	}

      emul:
	fpuemuprivate.stats.emulated++;
	switch (MIPSInst_OPCODE(ir)) {
#ifdef CP0_STATUS_FR_SUPPORT
		/* R4000+ 64-bit fpu registers */
#ifndef SINGLE_ONLY_FPU
	case ldc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			int ft = MIPSInst_RT(ir);
			if (!(xcp->cp0_status & ST0_FR))
				ft &= ~1;
			ctx->regs[ft] = mips_get_dword(xcp, va, &err);
			fpuemuprivate.stats.loads++;
			if (err) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;

	case sdc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			int ft = MIPSInst_RT(ir);
			if (!(xcp->cp0_status & ST0_FR))
				ft &= ~1;
			fpuemuprivate.stats.stores++;
			if (mips_put_dword(xcp, va, ctx->regs[ft])) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;
#endif

	case lwc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			fpureg_t val;
			int ft = MIPSInst_RT(ir);
			fpuemuprivate.stats.loads++;
			val = mips_get_word(xcp, va, &err);
			if (err) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
			if (xcp->cp0_status & ST0_FR) {
				/* load whole register */
				ctx->regs[ft] = val;
			} else if (ft & 1) {
				/* load to m.s. 32 bits */
#ifdef SINGLE_ONLY_FPU
				/* illegal register in single-float mode */
				return SIGILL;
#else
				ctx->regs[(ft & ~1)] &= 0xffffffff;
				ctx->regs[(ft & ~1)] |= val << 32;
#endif
			} else {
				/* load to l.s. 32 bits */
				ctx->regs[ft] &= ~0xffffffffLL;
				ctx->regs[ft] |= val;
			}
		}
		break;

	case swc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			unsigned int val;
			int ft = MIPSInst_RT(ir);
			fpuemuprivate.stats.stores++;
			if (xcp->cp0_status & ST0_FR) {
				/* store whole register */
				val = ctx->regs[ft];
			} else if (ft & 1) {
#ifdef SINGLE_ONLY_FPU
				/* illegal register in single-float mode */
				return SIGILL;
#else
				/* store from m.s. 32 bits */
				val = ctx->regs[(ft & ~1)] >> 32;
#endif
			} else {
				/* store from l.s. 32 bits */
				val = ctx->regs[ft];
			}
			if (mips_put_word(xcp, va, val)) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;
#else				/* old 32-bit fpu registers */
	case lwc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			ctx->regs[MIPSInst_RT(ir)] =
			    mips_get_word(xcp, va, &err);
			fpuemuprivate.stats.loads++;
			if (err) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;

	case swc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			fpuemuprivate.stats.stores++;
			if (mips_put_word
			    (xcp, va, ctx->regs[MIPSInst_RT(ir)])) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;
	case ldc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			unsigned int rt = MIPSInst_RT(ir) & ~1;
			int errs = 0;
			fpuemuprivate.stats.loads++;
#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
			ctx->regs[rt + 1] =
			    mips_get_word(xcp, va + 0, &err);
			errs += err;
			ctx->regs[rt + 0] =
			    mips_get_word(xcp, va + 4, &err);
			errs += err;
#else
			ctx->regs[rt + 0] =
			    mips_get_word(xcp, va + 0, &err);
			errs += err;
			ctx->regs[rt + 1] =
			    mips_get_word(xcp, va + 4, &err);
			errs += err;
#endif
			if (err)
				return SIGBUS;
		}
		break;

	case sdc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			unsigned int rt = MIPSInst_RT(ir) & ~1;
			fpuemuprivate.stats.stores++;
#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
			if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1]))
				return SIGBUS;
			if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0]))
				return SIGBUS;
#else
			if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0]))
				return SIGBUS;
			if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1]))
				return SIGBUS;
#endif
		}
		break;
#endif

	case cop1_op:
		switch (MIPSInst_RS(ir)) {

#ifdef CP0_STATUS_FR_SUPPORT
#if __mips64 && !defined(SINGLE_ONLY_FPU)
		case dmfc_op:
			/* copregister fs -> gpr[rt] */
			if (MIPSInst_RT(ir) != 0) {
				int fs = MIPSInst_RD(ir);
				if (!(xcp->cp0_status & ST0_FR))
					fs &= ~1;
				xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs];
			}
			break;

		case dmtc_op:
			/* copregister fs <- rt */
			{
				fpureg_t value;
				int fs = MIPSInst_RD(ir);
				if (!(xcp->cp0_status & ST0_FR))
					fs &= ~1;
				value =
				    (MIPSInst_RT(ir) ==
				     0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
				ctx->regs[fs] = value;
			}
			break;
#endif

		case mfc_op:
			/* copregister rd -> gpr[rt] */
			if (MIPSInst_RT(ir) != 0) {
				/* default value from l.s. 32 bits */
				int value = ctx->regs[MIPSInst_RD(ir)];
				if (MIPSInst_RD(ir) & 1) {
#ifdef SINGLE_ONLY_FPU
					/* illegal register in single-float mode */
					return SIGILL;
#else
					if (!(xcp->cp0_status & ST0_FR)) {
						/* move from m.s. 32 bits */
						value =
						    ctx->
						    regs[MIPSInst_RD(ir) &
							 ~1] >> 32;
					}
#endif
				}
				xcp->regs[MIPSInst_RT(ir)] = value;
			}