X86 : Improved instruction dumping

This commit is contained in:
PatrickvL 2018-09-24 15:19:59 +02:00
parent 9487ec09a7
commit fc3f0161bf
2 changed files with 70 additions and 27 deletions

View File

@ -2547,34 +2547,74 @@ char *Distorm_OpcodeString(const int opcode)
}
}
void output_value(std::stringstream &output, int nibbles, uint32_t value)
{
if (value < 0xA)
output << std::setw(1) << value;
else
output << std::setfill('0') << std::setw(nibbles) << std::right << value << 'h';
}
void output_value_disp(std::stringstream &output, int nibbles, uint32_t value)
{
if (value != 0) {
if ((int32_t)value < 0) {
output << '-';
output_value(output, nibbles, -value);
}
else {
output << '+';
output_value(output, nibbles, value);
}
}
}
void EmuX86_DistormLogInstruction(const uint8_t *Eip, _DInst &info)
{
std::stringstream output;
output
//<< std::setfill('0')
<< std::setw(8) << std::hex
<< "Processed instruction : "
<< (xbaddr)Eip
// << " "
// << std::setw(8) << *((uint8_t*)info.addr)
<< " "
<< Distorm_OpcodeString(info.opcode)
;
output << "Disassembly : "
<< std::setfill('0') << std::setw(8) << std::right << std::hex << std::uppercase << (xbaddr)Eip;
for (int b = 0; b < MAX(7, info.size); b++) {
if (b < info.size)
//output << " " << std::setfill('0') << std::setw(2) << std::right << std::hex << ((uint8_t)0+Eip[b]); // add 2 hex nibbles, not chars
output << " " << std::setw(2) << ((uint8_t)0+Eip[b]); // add 2 hex nibbles, not chars
else
output << " ";
}
output << " " << std::setfill(' ') << std::left << std::setw(11) << Distorm_OpcodeString(info.opcode);
for (int o = 0; o < 4 && info.ops[o].type != O_NONE; o++) {
output << ((o == 0) ? " " : ",");
//output << std::setw(info.ops[o].size / 4); // Convert size in bits to (hexadecimal) nibble count
// Convert size in bits to (hexadecimal) nibble count
int nr_nibbles = info.ops[o].size / 4;
std::string size_str;
output << std::setfill(' ') << std::setw(1) << std::right << ((o == 0) ? " " : ",");
switch (info.ops[o].size) {
case 8: size_str = "byte ptr "; break;
case 16: size_str = "word ptr "; break;
case 32: size_str = "dword ptr "; break;
default: nr_nibbles = 8; size_str = ""; break;
}
switch (info.ops[o].type) {
case O_REG: output << Distorm_RegStrings[info.ops[o].index]; break;
case O_IMM: output << info.imm.dword; break;
case O_IMM1: output << info.imm.ex.i1; break;
case O_IMM2: output << info.imm.ex.i2; break;
case O_DISP: output << "dword ptr ds:[" << info.disp << "]"; break;
case O_SMEM: output << "dword ptr [" << Distorm_RegStrings[info.ops[o].index] << "+" << info.disp << "]"; break;
case O_MEM: output << "[" << Distorm_RegStrings[info.ops[o].index] << "*?]"; break; // TODO O_MEM : complex memory dereference (optional fields : s / i / b / disp).
case O_PC: output << (xbaddr)Eip + INSTRUCTION_GET_TARGET(&info); break;
case O_PTR: output << "+" << info.imm.ptr.seg << "/" << info.imm.ptr.off; break;
default: output << "?"; break;
case O_REG: output << Distorm_RegStrings[info.ops[o].index]; break;
case O_IMM: output_value(output, nr_nibbles, info.imm.dword); break;
case O_IMM1: output_value(output, nr_nibbles, info.imm.ex.i1); break;
case O_IMM2: output_value(output, nr_nibbles, info.imm.ex.i2); break;
case O_DISP: output << size_str << "ds:[";
output_value(output, nr_nibbles, info.disp);
output << "]"; break;
case O_SMEM: output << size_str << "[" << Distorm_RegStrings[info.ops[o].index];
output_value_disp(output, nr_nibbles, info.disp);
output << "]"; break;
case O_MEM: output << size_str << "[" << Distorm_RegStrings[info.base] << "+" << Distorm_RegStrings[info.ops[o].index];
if (info.scale >= 2) {
output << "*"; output_value(output, 1, info.scale);
}
output_value_disp(output, nr_nibbles, info.disp);
output << "]"; break;
case O_PC: output_value(output, 8, (xbaddr)Eip + (xbaddr)INSTRUCTION_GET_TARGET(&info)); break;
case O_PTR: output << "+" << std::setfill('0') << info.imm.ptr.seg << "/";
output_value(output, nr_nibbles, info.imm.ptr.off); break;
default: output << "?"; break;
}
}
@ -2794,6 +2834,9 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
if (EmuX86_Opcode_LEA(e, info)) break;
goto opcode_error;
}
case I_LEAVE:
// LEAVE often precedes RET - end of a code block
return true;
case I_LFENCE: { // = 4287 : Serializes load operations.
__asm { lfence }; // emulate as-is (doesn't cause exceptions)
break;
@ -2942,7 +2985,7 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
if (EmuX86_Opcode_XOR(e, info)) break;
goto opcode_error;
default:
EmuLog(LOG_PREFIX, LOG_LEVEL::WARNING, "Unhandled instruction : %u", info.opcode);
EmuLog(LOG_PREFIX, LOG_LEVEL::WARNING, "Unhandled instruction : %s (%u)", Distorm_OpcodeString(info.opcode), info.opcode);
// Fail if the first hit instruction couldn't be emulated,
// but let host CPU execute following (unhandled) instructions :
return (StartingEip != e->ContextRecord->Eip);

View File

@ -164,11 +164,11 @@ static void update_irq(NV2AState *d)
#include "EmuNV2A_DEBUG.cpp"
#define DEBUG_READ32(DEV) DBG_PRINTF_EX(CXBXR_MODULE::X86, "Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Handled %s]\n", addr, result, DebugNV_##DEV##(addr))
#define DEBUG_READ32_UNHANDLED(DEV) { DBG_PRINTF_EX(CXBXR_MODULE::X86, "Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Unhandled %s]\n", addr, result, DebugNV_##DEV##(addr)); return result; }
#define DEBUG_READ32(DEV) DBG_PRINTF("Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Handled %s]\n", addr, result, DebugNV_##DEV##(addr))
#define DEBUG_READ32_UNHANDLED(DEV) { DBG_PRINTF("Rd32 NV2A " #DEV "(0x%08X) = 0x%08X [Unhandled %s]\n", addr, result, DebugNV_##DEV##(addr)); return result; }
#define DEBUG_WRITE32(DEV) DBG_PRINTF_EX(CXBXR_MODULE::X86, "Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Handled %s]\n", addr, value, DebugNV_##DEV##(addr))
#define DEBUG_WRITE32_UNHANDLED(DEV) { DBG_PRINTF_EX(CXBXR_MODULE::X86, "Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Unhandled %s]\n", addr, value, DebugNV_##DEV##(addr)); return; }
#define DEBUG_WRITE32(DEV) DBG_PRINTF("Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Handled %s]\n", addr, value, DebugNV_##DEV##(addr))
#define DEBUG_WRITE32_UNHANDLED(DEV) { DBG_PRINTF("Wr32 NV2A " #DEV "(0x%08X, 0x%08X) [Unhandled %s]\n", addr, value, DebugNV_##DEV##(addr)); return; }
#define DEVICE_READ32(DEV) uint32_t EmuNV2A_##DEV##_Read32(NV2AState *d, xbaddr addr)
#define DEVICE_READ32_SWITCH() uint32_t result = 0; switch (addr)