Exemplo n.º 1
0
	bool getDataAccessInfo(MipsOpcodeInfo& info)
	{
		int size = 0;
		
		u32 op = info.encodedOpcode;
		int off = 0;
		switch (MIPS_GET_OP(op))
		{
		case 0x20:		// lb
		case 0x24:		// lbu
		case 0x28:		// sb
			size = 1;
			break;
		case 0x21:		// lh
		case 0x25:		// lhu
		case 0x29:		// sh
			size = 2;
			break;
		case 0x23:		// lw
		case 0x26:		// lwr
		case 0x2B:		// sw
		case 0x2E:		// swr
			size = 4;
			break;
		case 0x22:		// lwl
		case 0x2A:		// swl
			size = 4;
			off = -3;
			break;
		case 0x37:		// ld
		case 0x1B:		// ldr
		case 0x3F:		// sd
		case 0x2D:		// sdr
			size = 8;
			break;
		case 0x1A:		// ldl
		case 0x2C:		// sdl
			size = 8;
			off = -7;
			break;
		}

		if (size == 0)
			return false;

		info.isDataAccess = true;
		info.dataSize = size;

		u32 rs = info.cpu->getRegister(0, (int)MIPS_GET_RS(op));
		s16 imm16 = op & 0xFFFF;
		info.dataAddress = rs + imm16 + off;

		info.hasRelevantAddress = true;
		info.releventAddress = info.dataAddress;
		return true;
	}
Exemplo n.º 2
0
	MipsOpcodeInfo GetOpcodeInfo(DebugInterface* cpu, u32 address) {
		MipsOpcodeInfo info;
		memset(&info, 0, sizeof(info));

		if (cpu->isValidAddress(address) == false) {
			return info;
		}

		info.cpu = cpu;
		info.opcodeAddress = address;
		info.encodedOpcode = cpu->read32(address);
		u32 op = info.encodedOpcode;

		if (getBranchInfo(info) == true)
			return info;

		if (getDataAccessInfo(info) == true)
			return info;

		// gather relevant address for alu operations
		// that's usually the value of the dest register
		switch (MIPS_GET_OP(op)) {
		case 0:		// special
			switch (MIPS_GET_FUNC(op)) {
			case 0x20:	// add
			case 0x21:	// addu
				info.hasRelevantAddress = true;
				info.releventAddress = cpu->getRegister(0,MIPS_GET_RS(op))._u32[0]+cpu->getRegister(0,MIPS_GET_RT(op))._u32[0];
				break;
			case 0x22:	// sub
			case 0x23:	// subu
				info.hasRelevantAddress = true;
				info.releventAddress = cpu->getRegister(0,MIPS_GET_RS(op))._u32[0]-cpu->getRegister(0,MIPS_GET_RT(op))._u32[0];
				break;
			}
			break;
		case 0x08:	// addi
		case 0x09:	// adiu
			info.hasRelevantAddress = true;
			info.releventAddress = cpu->getRegister(0,MIPS_GET_RS(op))._u32[0]+((s16)(op & 0xFFFF));
			break;
		}

		// TODO: rest
/*		// movn, movz
		if (opInfo & IS_CONDMOVE) {
			info.isConditional = true;

			u32 rt = cpu->GetRegValue(0, (int)MIPS_GET_RT(op));
			switch (opInfo & CONDTYPE_MASK) {
			case CONDTYPE_EQ:
				info.conditionMet = (rt == 0);
				break;
			case CONDTYPE_NE:
				info.conditionMet = (rt != 0);
				break;
			}
		}*/

		return info;
	}
Exemplo n.º 3
0
void DisassemblyFunction::load()
{
	generateBranchLines();

	// gather all branch targets
	std::set<u32> branchTargets;
	for (size_t i = 0; i < lines.size(); i++)
	{
		switch (lines[i].type)
		{
		case LINE_DOWN:
			branchTargets.insert(lines[i].second);
			break;
		case LINE_UP:
			branchTargets.insert(lines[i].first);
			break;
		default:
			break;
		}
	}
	
	DebugInterface* cpu = DisassemblyManager::getCpu();
	u32 funcPos = address;
	u32 funcEnd = address+size;

	u32 nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
	u32 opcodeSequenceStart = funcPos;
	while (funcPos < funcEnd)
	{
		if (funcPos == nextData)
		{
			if (opcodeSequenceStart != funcPos)
				addOpcodeSequence(opcodeSequenceStart,funcPos);

			DisassemblyData* data = new DisassemblyData(funcPos,symbolMap.GetDataSize(funcPos),symbolMap.GetDataType(funcPos));
			entries[funcPos] = data;
			lineAddresses.push_back(funcPos);
			funcPos += data->getTotalSize();

			nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
			opcodeSequenceStart = funcPos;
			continue;
		}

		// force align
		if (funcPos % 4)
		{
			u32 nextPos = (funcPos+3) & ~3;

			DisassemblyComment* comment = new DisassemblyComment(funcPos,nextPos-funcPos,".align","4");
			entries[funcPos] = comment;
			lineAddresses.push_back(funcPos);
			
			funcPos = nextPos;
			opcodeSequenceStart = funcPos;
			continue;
		}

		MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);
		u32 opAddress = funcPos;
		funcPos += 4;

		// skip branches and their delay slots
		if (opInfo.isBranch)
		{
			funcPos += 4;
			continue;
		}

		// lui
		if (MIPS_GET_OP(opInfo.encodedOpcode) == 0x0F && funcPos < funcEnd && funcPos != nextData)
		{
			MIPSOpcode next = Memory::Read_Instruction(funcPos);
			MIPSInfo nextInfo = MIPSGetInfo(next);

			u32 immediate = ((opInfo.encodedOpcode & 0xFFFF) << 16) + (s16)(next.encoding & 0xFFFF);
			int rt = MIPS_GET_RT(opInfo.encodedOpcode);

			int nextRs = MIPS_GET_RS(next.encoding);
			int nextRt = MIPS_GET_RT(next.encoding);

			// both rs and rt of the second op have to match rt of the first,
			// otherwise there may be hidden consequences if the macro is displayed.
			// also, don't create a macro if something branches into the middle of it
			if (nextRs == rt && nextRt == rt && branchTargets.find(funcPos) == branchTargets.end())
			{
				DisassemblyMacro* macro = NULL;
				switch (MIPS_GET_OP(next.encoding))
				{
				case 0x09:	// addiu
					macro = new DisassemblyMacro(opAddress);
					macro->setMacroLi(immediate,rt);
					funcPos += 4;
					break;
				case 0x20:	// lb
				case 0x21:	// lh
				case 0x23:	// lw
				case 0x24:	// lbu
				case 0x25:	// lhu
				case 0x28:	// sb
				case 0x29:	// sh
				case 0x2B:	// sw
					macro = new DisassemblyMacro(opAddress);
					
					int dataSize;
					switch (nextInfo & MEMTYPE_MASK) {
					case MEMTYPE_BYTE:
						dataSize = 1;
						break;
					case MEMTYPE_HWORD:
						dataSize = 2;
						break;
					case MEMTYPE_WORD:
					case MEMTYPE_FLOAT:
						dataSize = 4;
						break;
					case MEMTYPE_VQUAD:
						dataSize = 16;
						break;
					default:
						return;
					}

					macro->setMacroMemory(MIPSGetName(next),immediate,rt,dataSize);
					funcPos += 4;
					break;
				}

				if (macro != NULL)
				{
					if (opcodeSequenceStart != opAddress)
						addOpcodeSequence(opcodeSequenceStart,opAddress);

					entries[opAddress] = macro;
					for (int i = 0; i < macro->getNumLines(); i++)
					{
						lineAddresses.push_back(macro->getLineAddress(i));
					}

					opcodeSequenceStart = funcPos;
					continue;
				}
			}
		}

		// just a normal opcode
	}

	if (opcodeSequenceStart != funcPos)
		addOpcodeSequence(opcodeSequenceStart,funcPos);
}
Exemplo n.º 4
0
	bool getBranchInfo(MipsOpcodeInfo& info)
	{
		BranchType type = NONE;
		bool link = false;
		bool likely = false;
		bool toRegister = false;
		bool met = false;

		u32 op = info.encodedOpcode;

		u32 opNum = MIPS_GET_OP(op);
		u32 rsNum = MIPS_GET_RS(op);
		u32 rtNum = MIPS_GET_RT(op);
		u32 rs = info.cpu->getRegister(0,rsNum);
		u32 rt = info.cpu->getRegister(0,rtNum);

		switch (MIPS_GET_OP(op))
		{
		case 0x00:		// special
			switch (MIPS_GET_FUNC(op))
			{
			case 0x08:	// jr
				type = JUMP;
				toRegister = true;
				break;
			case 0x09:	// jalr
				type = JUMP;
				toRegister = true;
				link = true;
				break;
			}
			break;
		case 0x01:		// regimm
			switch (MIPS_GET_RT(op))
			{
			case 0x00:		// bltz
			case 0x02:		// bltzl
			case 0x10:		// bltzal
			case 0x12:		// bltzall
				type = BRANCH;
				met = (((s32)rs) < 0);
				likely = (rt & 2) != 0;
				link = rt >= 0x10;
				break;
				
			case 0x01:		// bgez
			case 0x03:		// bgezl
			case 0x11:		// bgezal
			case 0x13:		// bgezall
				type = BRANCH;
				met = (((s32)rs) >= 0);
				likely = (rt & 2) != 0;
				link = rt >= 0x10;
				break;
			}
			break;
		case 0x02:		// j
			type = JUMP;
			break;
		case 0x03:		// jal
			type = JUMP;
			link = true;
			break;
			
		case 0x04:		// beq
		case 0x14:		// beql
			type = BRANCH;
			met = (rt == rs);
			if (MIPS_GET_RT(op) == MIPS_GET_RS(op))	// always true
				info.isConditional = false;
			likely = opNum >= 0x10;
			break;
			
		case 0x05:		// bne
		case 0x15:		// bnel
			type = BRANCH;
			met = (rt != rs);
			if (MIPS_GET_RT(op) == MIPS_GET_RS(op))	// always false
				info.isConditional = false;
			likely = opNum >= 0x10;
			break;
			
		case 0x06:		// blez
		case 0x16:		// blezl
			type = BRANCH;
			met = (((s32)rs) <= 0);
			likely = opNum >= 0x10;
			break;

		case 0x07:		// bgtz
		case 0x17:		// bgtzl
			type = BRANCH;
			met = (((s32)rs) > 0);
			likely = opNum >= 0x10;
			break;
		}

		if (type == NONE)
			return false;

		info.isBranch = true;
		info.isLinkedBranch = link;
		info.isLikelyBranch = true;
		info.isBranchToRegister = toRegister;
		info.isConditional = type == BRANCH;
		info.conditionMet = met;

		switch (type)
		{
		case JUMP:
			if (toRegister)
			{
				info.branchRegisterNum = (int)MIPS_GET_RS(op);
				info.branchTarget = info.cpu->getRegister(0,info.branchRegisterNum)._u32[0];
			} else {
				info.branchTarget =  (info.opcodeAddress & 0xF0000000) | ((op&0x03FFFFFF) << 2);
			}
			break;
		case BRANCH:
			info.branchTarget = info.opcodeAddress + 4 + ((signed short)(op&0xFFFF)<<2);
			break;
		}

		return true;
	}
Exemplo n.º 5
0
void DisassemblyFunction::load()
{
	generateBranchLines();

	// gather all branch targets
	std::set<u32> branchTargets;
	for (size_t i = 0; i < lines.size(); i++)
	{
		switch (lines[i].type)
		{
		case LINE_DOWN:
			branchTargets.insert(lines[i].second);
			break;
		case LINE_UP:
			branchTargets.insert(lines[i].first);
			break;
		}
	}
	
	u32 funcPos = address;
	u32 funcEnd = address+size;

	u32 nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
	u32 opcodeSequenceStart = funcPos;
	while (funcPos < funcEnd)
	{
		if (funcPos == nextData)
		{
			if (opcodeSequenceStart != funcPos)
				addOpcodeSequence(opcodeSequenceStart,funcPos);

			DisassemblyData* data = new DisassemblyData(cpu,funcPos,symbolMap.GetDataSize(funcPos),symbolMap.GetDataType(funcPos));
			entries[funcPos] = data;
			lineAddresses.push_back(funcPos);
			funcPos += data->getTotalSize();

			nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
			opcodeSequenceStart = funcPos;
			continue;
		}

		// force align
		if (funcPos % 4)
		{
			u32 nextPos = (funcPos+3) & ~3;

			DisassemblyComment* comment = new DisassemblyComment(cpu,funcPos,nextPos-funcPos,".align","4");
			entries[funcPos] = comment;
			lineAddresses.push_back(funcPos);
			
			funcPos = nextPos;
			opcodeSequenceStart = funcPos;
			continue;
		}

		MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);
		u32 opAddress = funcPos;
		funcPos += 4;
		
		// skip branches and their delay slots
		if (opInfo.isBranch)
		{
			funcPos += 4;
			continue;
		}
		
		// lui
		if (MIPS_GET_OP(opInfo.encodedOpcode) == 0x0F && funcPos < funcEnd && funcPos != nextData)
		{
			u32 next = cpu->read32(funcPos);

			u32 immediate = ((opInfo.encodedOpcode & 0xFFFF) << 16) + (s16)(next & 0xFFFF);
			u32 immediateOr = ((opInfo.encodedOpcode & 0xFFFF) << 16) | (u16)(next & 0xFFFF);
			int rt = MIPS_GET_RT(opInfo.encodedOpcode);

			int nextRs = MIPS_GET_RS(next);
			int nextRt = MIPS_GET_RT(next);

			// both rs and rt of the second op have to match rt of the first,
			// otherwise there may be hidden consequences if the macro is displayed.
			// also, don't create a macro if something branches into the middle of it
			if (nextRs == rt && nextRt == rt && branchTargets.find(funcPos) == branchTargets.end())
			{
				DisassemblyMacro* macro = NULL;
				switch (MIPS_GET_OP(next))
				{
				case 0x09:	// addiu
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroLi(immediate,rt);
					funcPos += 4;
					break;
				case 0x0D:	// ori
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroLi(immediateOr,rt);
					funcPos += 4;
					break;
				case 0x20:	// lb
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroMemory("lb",immediate,rt,1);
					funcPos += 4;
					break;
				case 0x21:	// lh
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroMemory("lh",immediate,rt,2);
					funcPos += 4;
					break;
				case 0x23:	// lw
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroMemory("lw",immediate,rt,4);
					funcPos += 4;
					break;
				case 0x24:	// lbu
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroMemory("lbu",immediate,rt,1);
					funcPos += 4;
					break;
				case 0x25:	// lhu
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroMemory("lhu",immediate,rt,2);
					funcPos += 4;
					break;
				case 0x28:	// sb
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroMemory("sb",immediate,rt,1);
					funcPos += 4;
					break;
				case 0x29:	// sh
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroMemory("sh",immediate,rt,2);
					funcPos += 4;
				case 0x2B:	// sw
					macro = new DisassemblyMacro(cpu,opAddress);
					macro->setMacroMemory("sw",immediate,rt,4);
					funcPos += 4;
					break;
				}

				if (macro != NULL)
				{
					if (opcodeSequenceStart != opAddress)
						addOpcodeSequence(opcodeSequenceStart,opAddress);

					entries[opAddress] = macro;
					for (int i = 0; i < macro->getNumLines(); i++)
					{
						lineAddresses.push_back(macro->getLineAddress(i));
					}

					opcodeSequenceStart = funcPos;
					continue;
				}
			}
		}

		// just a normal opcode
	}

	if (opcodeSequenceStart != funcPos)
		addOpcodeSequence(opcodeSequenceStart,funcPos);
}