Adapt x86-64 to also use udis86-based instruction analysis.

This commit is contained in:
Rene Gollent 2013-01-06 11:43:41 -05:00
parent 59fcd81013
commit dcce0a030b
4 changed files with 137 additions and 33 deletions

View File

@ -470,9 +470,8 @@ status_t
ArchitectureX8664::GetInstructionInfo(target_addr_t address,
InstructionInfo& _info, CpuState* state)
{
// read the code
// read the code - maximum x86{-64} instruction size = 15 bytes
uint8 buffer[16];
// TODO: What's the maximum instruction size?
ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer,
sizeof(buffer));
if (bytesRead < 0)
@ -484,37 +483,7 @@ ArchitectureX8664::GetInstructionInfo(target_addr_t address,
if (error != B_OK)
return error;
// disassemble the instruction
BString line;
target_addr_t instructionAddress;
target_addr_t targetAddress = 0;
target_size_t instructionSize;
bool breakpointAllowed;
error = disassembler.GetNextInstruction(line, instructionAddress,
instructionSize, breakpointAllowed);
if (error != B_OK)
return error;
// FIXME: Is this correct for x86_64? I'm not entirely sure.
instruction_type instructionType = INSTRUCTION_TYPE_OTHER;
if (buffer[0] == 0xff && (buffer[1] & 0x34) == 0x10) {
// absolute call with r/m32
instructionType = INSTRUCTION_TYPE_SUBROUTINE_CALL;
} else if (buffer[0] == 0xe8 && instructionSize == 5) {
// relative call with rel32 -- don't categorize the call with 0 as
// subroutine call, since it is only used to get the address of the GOT
if (buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0
|| buffer[4] != 0) {
instructionType = INSTRUCTION_TYPE_SUBROUTINE_CALL;
}
}
if (!_info.SetTo(instructionAddress, targetAddress, instructionSize,
instructionType, breakpointAllowed, line)) {
return B_NO_MEMORY;
}
return B_OK;
return disassembler.GetNextInstructionInfo(_info, state);
}

View File

@ -14,6 +14,46 @@
#include <OS.h>
#include "CpuStateX8664.h"
#include "InstructionInfo.h"
static uint8 RegisterNumberFromUdisIndex(int32 udisIndex)
{
switch (udisIndex) {
case UD_R_RIP: return X86_64_REGISTER_RIP;
case UD_R_RSP: return X86_64_REGISTER_RSP;
case UD_R_RBP: return X86_64_REGISTER_RBP;
case UD_R_RAX: return X86_64_REGISTER_RAX;
case UD_R_RBX: return X86_64_REGISTER_RBX;
case UD_R_RCX: return X86_64_REGISTER_RCX;
case UD_R_RDX: return X86_64_REGISTER_RDX;
case UD_R_RSI: return X86_64_REGISTER_RSI;
case UD_R_RDI: return X86_64_REGISTER_RDI;
case UD_R_R8: return X86_64_REGISTER_R8;
case UD_R_R9: return X86_64_REGISTER_R9;
case UD_R_R10: return X86_64_REGISTER_R10;
case UD_R_R11: return X86_64_REGISTER_R11;
case UD_R_R12: return X86_64_REGISTER_R12;
case UD_R_R13: return X86_64_REGISTER_R13;
case UD_R_R14: return X86_64_REGISTER_R14;
case UD_R_R15: return X86_64_REGISTER_R15;
case UD_R_CS: return X86_64_REGISTER_CS;
case UD_R_DS: return X86_64_REGISTER_DS;
case UD_R_ES: return X86_64_REGISTER_ES;
case UD_R_FS: return X86_64_REGISTER_FS;
case UD_R_GS: return X86_64_REGISTER_GS;
case UD_R_SS: return X86_64_REGISTER_SS;
}
return X86_64_INT_REGISTER_END;
}
struct DisassemblerX8664::UdisData : ud_t {
};
@ -109,3 +149,85 @@ DisassemblerX8664::GetPreviousInstruction(target_addr_t nextAddress,
}
}
}
status_t
DisassemblerX8664::GetNextInstructionInfo(InstructionInfo& _info,
CpuState* state)
{
unsigned int size = ud_disassemble(fUdisData);
if (size < 1)
return B_ENTRY_NOT_FOUND;
uint32 address = (uint32)ud_insn_off(fUdisData);
instruction_type type = INSTRUCTION_TYPE_OTHER;
target_addr_t targetAddress = 0;
if (fUdisData->mnemonic == UD_Icall)
type = INSTRUCTION_TYPE_SUBROUTINE_CALL;
else if (fUdisData->mnemonic == UD_Ijmp)
type = INSTRUCTION_TYPE_JUMP;
if (state != NULL)
targetAddress = GetInstructionTargetAddress(state);
char buffer[256];
snprintf(buffer, sizeof(buffer), "0x%08" B_PRIx32 ": %16.16s %s", address,
ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
// TODO: Resolve symbols!
if (!_info.SetTo(address, targetAddress, size, type, true, buffer))
return B_NO_MEMORY;
return B_OK;
}
target_addr_t
DisassemblerX8664::GetInstructionTargetAddress(CpuState* state) const
{
if (fUdisData->mnemonic != UD_Icall && fUdisData->mnemonic != UD_Ijmp)
return 0;
CpuStateX8664* x64State = dynamic_cast<CpuStateX8664*>(state);
if (x64State == NULL)
return 0;
target_addr_t targetAddress = 0;
switch (fUdisData->operand[0].type) {
case UD_OP_REG:
{
targetAddress = x64State->IntRegisterValue(
RegisterNumberFromUdisIndex(fUdisData->operand[0].base));
targetAddress += fUdisData->operand[0].offset;
}
break;
case UD_OP_MEM:
{
targetAddress = x64State->IntRegisterValue(
RegisterNumberFromUdisIndex(fUdisData->operand[0].base));
targetAddress += x64State->IntRegisterValue(
RegisterNumberFromUdisIndex(fUdisData->operand[0].index))
* fUdisData->operand[0].scale;
}
break;
case UD_OP_JIMM:
{
targetAddress = ud_insn_off(fUdisData)
+ fUdisData->operand[0].lval.sdword + ud_insn_len(fUdisData);
}
break;
case UD_OP_IMM:
case UD_OP_CONST:
{
targetAddress = fUdisData->operand[0].lval.udword;
}
break;
default:
break;
}
return targetAddress;
}

View File

@ -11,6 +11,10 @@
#include "Types.h"
class CpuState;
class InstructionInfo;
class DisassemblerX8664 {
public:
DisassemblerX8664();
@ -27,7 +31,13 @@ public:
target_addr_t nextAddress,
target_addr_t& _address,
target_size_t& _size);
virtual status_t GetNextInstructionInfo(
InstructionInfo& _info,
CpuState* state);
private:
target_addr_t GetInstructionTargetAddress(
CpuState* state) const;
private:
struct UdisData;

View File

@ -3,9 +3,12 @@ SubDir HAIKU_TOP src apps debugger arch x86_64 disasm ;
CCFLAGS += -Werror ;
C++FLAGS += -Werror ;
UsePrivateHeaders shared ;
UseHeaders [ LibraryHeaders udis86 ] ;
UseHeaders [ LibraryHeaders [ FDirName udis86 libudis86 ] ] ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) types ] ;