Debugger: switch to zydis for x86 and x86_64
Change-Id: Iec6d21bc989c3d532c175fd78a2339fede3df1dd Reviewed-on: https://review.haiku-os.org/c/haiku/+/7849 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
06b1eff6ec
commit
34b59fca80
@@ -347,7 +347,7 @@ SharedLibrary libdebugger.so :
|
|||||||
<nogrist>Debugger_disasm_x86_64.o
|
<nogrist>Debugger_disasm_x86_64.o
|
||||||
<nogrist>Debugger_dwarf.o
|
<nogrist>Debugger_dwarf.o
|
||||||
|
|
||||||
libudis86.a
|
libzydis.a
|
||||||
<bin>debug_utils.a
|
<bin>debug_utils.a
|
||||||
shared
|
shared
|
||||||
|
|
||||||
|
|||||||
@@ -9,42 +9,36 @@
|
|||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include "udis86.h"
|
#include "Zycore/Format.h"
|
||||||
|
#include "Zydis/Zydis.h"
|
||||||
|
|
||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
|
|
||||||
#include "CpuStateX86.h"
|
#include "CpuStateX86.h"
|
||||||
#include "InstructionInfo.h"
|
#include "InstructionInfo.h"
|
||||||
|
|
||||||
|
|
||||||
static uint8 RegisterNumberFromUdisIndex(int32 udisIndex)
|
void
|
||||||
|
CpuStateToZydisRegContext(CpuStateX86* state, ZydisRegisterContext* context)
|
||||||
{
|
{
|
||||||
switch (udisIndex) {
|
context->values[ZYDIS_REGISTER_EAX] = state->IntRegisterValue(X86_REGISTER_EAX);
|
||||||
case UD_R_RIP: return X86_REGISTER_EIP;
|
context->values[ZYDIS_REGISTER_ESP] = state->IntRegisterValue(X86_REGISTER_ESP);
|
||||||
case UD_R_ESP: return X86_REGISTER_ESP;
|
context->values[ZYDIS_REGISTER_EIP] = state->IntRegisterValue(X86_REGISTER_EIP);
|
||||||
case UD_R_EBP: return X86_REGISTER_EBP;
|
// context->values[ZYDIS_REGISTER_RFLAGS] = eflags;
|
||||||
|
context->values[ZYDIS_REGISTER_ECX] = state->IntRegisterValue(X86_REGISTER_ECX);
|
||||||
case UD_R_EAX: return X86_REGISTER_EAX;
|
context->values[ZYDIS_REGISTER_EDX] = state->IntRegisterValue(X86_REGISTER_EDX);
|
||||||
case UD_R_EBX: return X86_REGISTER_EBX;
|
context->values[ZYDIS_REGISTER_EBX] = state->IntRegisterValue(X86_REGISTER_EBX);
|
||||||
case UD_R_ECX: return X86_REGISTER_ECX;
|
context->values[ZYDIS_REGISTER_EBP] = state->IntRegisterValue(X86_REGISTER_EBP);
|
||||||
case UD_R_EDX: return X86_REGISTER_EDX;
|
context->values[ZYDIS_REGISTER_ESI] = state->IntRegisterValue(X86_REGISTER_ESI);
|
||||||
|
context->values[ZYDIS_REGISTER_EDI] = state->IntRegisterValue(X86_REGISTER_EDI);
|
||||||
case UD_R_ESI: return X86_REGISTER_ESI;
|
|
||||||
case UD_R_EDI: return X86_REGISTER_EDI;
|
|
||||||
|
|
||||||
case UD_R_CS: return X86_REGISTER_CS;
|
|
||||||
case UD_R_DS: return X86_REGISTER_DS;
|
|
||||||
case UD_R_ES: return X86_REGISTER_ES;
|
|
||||||
case UD_R_FS: return X86_REGISTER_FS;
|
|
||||||
case UD_R_GS: return X86_REGISTER_GS;
|
|
||||||
case UD_R_SS: return X86_REGISTER_SS;
|
|
||||||
}
|
|
||||||
|
|
||||||
return X86_INT_REGISTER_END;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct DisassemblerX86::UdisData : ud_t {
|
struct DisassemblerX86::ZydisData {
|
||||||
|
ZydisDecoder decoder ;
|
||||||
|
ZydisFormatter formatter;
|
||||||
|
ZyanUSize offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -53,14 +47,14 @@ DisassemblerX86::DisassemblerX86()
|
|||||||
fAddress(0),
|
fAddress(0),
|
||||||
fCode(NULL),
|
fCode(NULL),
|
||||||
fCodeSize(0),
|
fCodeSize(0),
|
||||||
fUdisData(NULL)
|
fZydisData(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DisassemblerX86::~DisassemblerX86()
|
DisassemblerX86::~DisassemblerX86()
|
||||||
{
|
{
|
||||||
delete fUdisData;
|
delete fZydisData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -68,25 +62,33 @@ status_t
|
|||||||
DisassemblerX86::Init(target_addr_t address, const void* code, size_t codeSize)
|
DisassemblerX86::Init(target_addr_t address, const void* code, size_t codeSize)
|
||||||
{
|
{
|
||||||
// unset old data
|
// unset old data
|
||||||
delete fUdisData;
|
delete fZydisData;
|
||||||
fUdisData = NULL;
|
fZydisData = NULL;
|
||||||
|
|
||||||
// set new data
|
// set new data
|
||||||
fUdisData = new(std::nothrow) UdisData;
|
fZydisData = new(std::nothrow) ZydisData;
|
||||||
if (fUdisData == NULL)
|
if (fZydisData == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
fAddress = address;
|
fAddress = address;
|
||||||
fCode = (const uint8*)code;
|
fCode = (const uint8*)code;
|
||||||
fCodeSize = codeSize;
|
fCodeSize = codeSize;
|
||||||
|
|
||||||
// init udis
|
// init zydis
|
||||||
ud_init(fUdisData);
|
fZydisData->offset = 0;
|
||||||
ud_set_input_buffer(fUdisData, (unsigned char*)fCode, fCodeSize);
|
ZydisDecoderInit(&fZydisData->decoder, ZYDIS_MACHINE_MODE_LEGACY_32, ZYDIS_STACK_WIDTH_32);
|
||||||
ud_set_mode(fUdisData, 32);
|
ZydisFormatterInit(&fZydisData->formatter, ZYDIS_FORMATTER_STYLE_ATT);
|
||||||
ud_set_pc(fUdisData, (uint64_t)fAddress);
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE);
|
||||||
ud_set_syntax(fUdisData, UD_SYN_ATT);
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_HEX_UPPERCASE,
|
||||||
ud_set_vendor(fUdisData, UD_VENDOR_INTEL);
|
ZYAN_FALSE);
|
||||||
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_ABSOLUTE,
|
||||||
|
ZYDIS_PADDING_DISABLED);
|
||||||
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_RELATIVE,
|
||||||
|
ZYDIS_PADDING_DISABLED);
|
||||||
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_DISP_PADDING,
|
||||||
|
ZYDIS_PADDING_DISABLED);
|
||||||
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_IMM_PADDING,
|
||||||
|
ZYDIS_PADDING_DISABLED);
|
||||||
// TODO: Set the correct vendor!
|
// TODO: Set the correct vendor!
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -97,20 +99,36 @@ status_t
|
|||||||
DisassemblerX86::GetNextInstruction(BString& line, target_addr_t& _address,
|
DisassemblerX86::GetNextInstruction(BString& line, target_addr_t& _address,
|
||||||
target_size_t& _size, bool& _breakpointAllowed)
|
target_size_t& _size, bool& _breakpointAllowed)
|
||||||
{
|
{
|
||||||
unsigned int size = ud_disassemble(fUdisData);
|
const uint8* buffer = fCode + fZydisData->offset;
|
||||||
if (size < 1)
|
ZydisDecodedInstruction instruction;
|
||||||
|
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||||
|
if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&fZydisData->decoder, buffer,
|
||||||
|
fCodeSize - fZydisData->offset, &instruction, operands))) {
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 address = (uint32)ud_insn_off(fUdisData);
|
uint32 address = (uint32)(fAddress + fZydisData->offset);
|
||||||
|
fZydisData->offset += instruction.length;
|
||||||
|
|
||||||
char buffer[256];
|
char hexString[32];
|
||||||
snprintf(buffer, sizeof(buffer), "0x%08" B_PRIx32 ": %16.16s %s", address,
|
char* srcHex = hexString;
|
||||||
ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
|
for (ZyanUSize i = 0; i < instruction.length; i++) {
|
||||||
// TODO: Resolve symbols!
|
sprintf(srcHex, "%02" PRIx8, buffer[i]);
|
||||||
|
srcHex += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char formatted[1024];
|
||||||
|
if (ZYAN_SUCCESS(ZydisFormatterFormatInstruction(&fZydisData->formatter, &instruction,
|
||||||
|
operands, instruction.operand_count_visible, formatted, sizeof(formatted), address,
|
||||||
|
NULL))) {
|
||||||
|
line.SetToFormat("0x%08" B_PRIx32 ": %16.16s %s", address, hexString, formatted);
|
||||||
|
} else {
|
||||||
|
line.SetToFormat("0x%08" B_PRIx32 ": failed-to-format", address);
|
||||||
|
}
|
||||||
|
// TODO: Resolve symbols!
|
||||||
|
|
||||||
line = buffer;
|
|
||||||
_address = address;
|
_address = address;
|
||||||
_size = size;
|
_size = instruction.length;
|
||||||
_breakpointAllowed = true;
|
_breakpointAllowed = true;
|
||||||
// TODO: Implement (rep!)!
|
// TODO: Implement (rep!)!
|
||||||
|
|
||||||
@@ -127,14 +145,19 @@ DisassemblerX86::GetPreviousInstruction(target_addr_t nextAddress,
|
|||||||
|
|
||||||
// loop until hitting the last instruction
|
// loop until hitting the last instruction
|
||||||
while (true) {
|
while (true) {
|
||||||
unsigned int size = ud_disassemble(fUdisData);
|
const uint8* buffer = fCode + fZydisData->offset;
|
||||||
if (size < 1)
|
ZydisDecodedInstruction instruction;
|
||||||
|
if (!ZYAN_SUCCESS(ZydisDecoderDecodeInstruction(&fZydisData->decoder,
|
||||||
|
(ZydisDecoderContext*)ZYAN_NULL, buffer, fCodeSize - fZydisData->offset,
|
||||||
|
&instruction))) {
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 address = (uint32)ud_insn_off(fUdisData);
|
fZydisData->offset += instruction.length;
|
||||||
if (address + size == nextAddress) {
|
target_addr_t address = fAddress + fZydisData->offset;
|
||||||
|
if (address == nextAddress) {
|
||||||
_address = address;
|
_address = address;
|
||||||
_size = size;
|
_size = instruction.length;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,84 +168,55 @@ status_t
|
|||||||
DisassemblerX86::GetNextInstructionInfo(InstructionInfo& _info,
|
DisassemblerX86::GetNextInstructionInfo(InstructionInfo& _info,
|
||||||
CpuState* state)
|
CpuState* state)
|
||||||
{
|
{
|
||||||
unsigned int size = ud_disassemble(fUdisData);
|
const uint8* buffer = fCode + fZydisData->offset;
|
||||||
if (size < 1)
|
ZydisDecodedInstruction instruction;
|
||||||
|
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||||
|
if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&fZydisData->decoder, buffer,
|
||||||
|
fCodeSize - fZydisData->offset, &instruction, operands))) {
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 address = (uint32)ud_insn_off(fUdisData);
|
uint32 address = (uint32)(fAddress + fZydisData->offset);
|
||||||
|
fZydisData->offset += instruction.length;
|
||||||
|
|
||||||
|
char hexString[32];
|
||||||
|
char* srcHex = hexString;
|
||||||
|
for (ZyanUSize i = 0; i < instruction.length; i++) {
|
||||||
|
sprintf(srcHex, "%02" PRIx8, buffer[i]);
|
||||||
|
srcHex += 2;
|
||||||
|
}
|
||||||
|
|
||||||
instruction_type type = INSTRUCTION_TYPE_OTHER;
|
instruction_type type = INSTRUCTION_TYPE_OTHER;
|
||||||
target_addr_t targetAddress = 0;
|
target_addr_t targetAddress = 0;
|
||||||
|
if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL)
|
||||||
ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData);
|
|
||||||
if (mnemonic == UD_Icall)
|
|
||||||
type = INSTRUCTION_TYPE_SUBROUTINE_CALL;
|
type = INSTRUCTION_TYPE_SUBROUTINE_CALL;
|
||||||
else if (mnemonic == UD_Ijmp)
|
else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP)
|
||||||
type = INSTRUCTION_TYPE_JUMP;
|
type = INSTRUCTION_TYPE_JUMP;
|
||||||
if (state != NULL)
|
if (state != NULL) {
|
||||||
targetAddress = GetInstructionTargetAddress(state);
|
CpuStateX86* x86State = dynamic_cast<CpuStateX86*>(state);
|
||||||
|
if (x86State != NULL) {
|
||||||
|
ZydisRegisterContext registers;
|
||||||
|
CpuStateToZydisRegContext(x86State, ®isters);
|
||||||
|
ZYAN_CHECK(ZydisCalcAbsoluteAddressEx(&instruction, operands,
|
||||||
|
address, ®isters, &targetAddress));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char buffer[256];
|
char string[1024];
|
||||||
snprintf(buffer, sizeof(buffer), "0x%08" B_PRIx32 ": %16.16s %s", address,
|
int written = snprintf(string, sizeof(string), "0x%08" B_PRIx32 ": %16.16s ", address,
|
||||||
ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
|
hexString);
|
||||||
// TODO: Resolve symbols!
|
char* formatted = string + written;
|
||||||
|
if (!ZYAN_SUCCESS(ZydisFormatterFormatInstruction(&fZydisData->formatter, &instruction,
|
||||||
|
operands, instruction.operand_count_visible, formatted, sizeof(string) - written, address,
|
||||||
|
NULL))) {
|
||||||
|
snprintf(string, sizeof(string), "0x%08" B_PRIx32 ": failed-to-format", address);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_info.SetTo(address, targetAddress, size, type, true, buffer))
|
// TODO: Resolve symbols!
|
||||||
|
|
||||||
|
if (!_info.SetTo(address, targetAddress, instruction.length, type, true, string))
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
target_addr_t
|
|
||||||
DisassemblerX86::GetInstructionTargetAddress(CpuState* state) const
|
|
||||||
{
|
|
||||||
ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData);
|
|
||||||
if (mnemonic != UD_Icall && mnemonic != UD_Ijmp)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CpuStateX86* x86State = dynamic_cast<CpuStateX86*>(state);
|
|
||||||
if (x86State == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
target_addr_t targetAddress = 0;
|
|
||||||
const struct ud_operand* op = ud_insn_opr(fUdisData, 0);
|
|
||||||
switch (op->type) {
|
|
||||||
case UD_OP_REG:
|
|
||||||
{
|
|
||||||
targetAddress = x86State->IntRegisterValue(
|
|
||||||
RegisterNumberFromUdisIndex(op->base));
|
|
||||||
targetAddress += op->offset;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UD_OP_MEM:
|
|
||||||
{
|
|
||||||
targetAddress = x86State->IntRegisterValue(
|
|
||||||
RegisterNumberFromUdisIndex(op->base));
|
|
||||||
targetAddress += x86State->IntRegisterValue(
|
|
||||||
RegisterNumberFromUdisIndex(op->index))
|
|
||||||
* op->scale;
|
|
||||||
if (op->offset != 0)
|
|
||||||
targetAddress += op->lval.sdword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UD_OP_JIMM:
|
|
||||||
{
|
|
||||||
targetAddress = ud_insn_off(fUdisData)
|
|
||||||
+ op->lval.sdword + ud_insn_len(fUdisData);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UD_OP_IMM:
|
|
||||||
case UD_OP_CONST:
|
|
||||||
{
|
|
||||||
targetAddress = op->lval.udword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetAddress;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -35,18 +35,14 @@ public:
|
|||||||
InstructionInfo& _info,
|
InstructionInfo& _info,
|
||||||
CpuState* state);
|
CpuState* state);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
target_addr_t GetInstructionTargetAddress(
|
struct ZydisData;
|
||||||
CpuState* state) const;
|
|
||||||
private:
|
|
||||||
struct UdisData;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
target_addr_t fAddress;
|
target_addr_t fAddress;
|
||||||
const uint8* fCode;
|
const uint8* fCode;
|
||||||
size_t fCodeSize;
|
size_t fCodeSize;
|
||||||
UdisData* fUdisData;
|
ZydisData* fZydisData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ UsePrivateHeaders shared ;
|
|||||||
UsePrivateHeaders [ FDirName debugger arch ] ;
|
UsePrivateHeaders [ FDirName debugger arch ] ;
|
||||||
UsePrivateHeaders [ FDirName debugger types ] ;
|
UsePrivateHeaders [ FDirName debugger types ] ;
|
||||||
|
|
||||||
UseHeaders [ LibraryHeaders udis86 ] ;
|
UseHeaders [ LibraryHeaders zydis ] : true ;
|
||||||
UseHeaders [ LibraryHeaders [ FDirName udis86 libudis86 ] ] ;
|
|
||||||
|
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
|
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
|
||||||
|
|
||||||
|
DEFINES += ZYDIS_DISABLE_ENCODER ;
|
||||||
|
|
||||||
MergeObject Debugger_disasm_x86.o
|
MergeObject Debugger_disasm_x86.o
|
||||||
:
|
:
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include "udis86.h"
|
#include "Zycore/Format.h"
|
||||||
|
#include "Zydis/Zydis.h"
|
||||||
|
|
||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
@@ -19,43 +20,34 @@
|
|||||||
#include "InstructionInfo.h"
|
#include "InstructionInfo.h"
|
||||||
|
|
||||||
|
|
||||||
static uint8 RegisterNumberFromUdisIndex(int32 udisIndex)
|
void
|
||||||
|
CpuStateToZydisRegContext(CpuStateX8664* state, ZydisRegisterContext* context)
|
||||||
{
|
{
|
||||||
switch (udisIndex) {
|
context->values[ZYDIS_REGISTER_RAX] = state->IntRegisterValue(X86_64_REGISTER_RAX);
|
||||||
case UD_R_RIP: return X86_64_REGISTER_RIP;
|
context->values[ZYDIS_REGISTER_RSP] = state->IntRegisterValue(X86_64_REGISTER_RSP);
|
||||||
case UD_R_RSP: return X86_64_REGISTER_RSP;
|
context->values[ZYDIS_REGISTER_RIP] = state->IntRegisterValue(X86_64_REGISTER_RIP);
|
||||||
case UD_R_RBP: return X86_64_REGISTER_RBP;
|
// context->values[ZYDIS_REGISTER_RFLAGS] = eflags;
|
||||||
|
context->values[ZYDIS_REGISTER_RCX] = state->IntRegisterValue(X86_64_REGISTER_RCX);
|
||||||
case UD_R_RAX: return X86_64_REGISTER_RAX;
|
context->values[ZYDIS_REGISTER_RDX] = state->IntRegisterValue(X86_64_REGISTER_RDX);
|
||||||
case UD_R_RBX: return X86_64_REGISTER_RBX;
|
context->values[ZYDIS_REGISTER_RBX] = state->IntRegisterValue(X86_64_REGISTER_RBX);
|
||||||
case UD_R_RCX: return X86_64_REGISTER_RCX;
|
context->values[ZYDIS_REGISTER_RBP] = state->IntRegisterValue(X86_64_REGISTER_RBP);
|
||||||
case UD_R_RDX: return X86_64_REGISTER_RDX;
|
context->values[ZYDIS_REGISTER_RSI] = state->IntRegisterValue(X86_64_REGISTER_RSI);
|
||||||
|
context->values[ZYDIS_REGISTER_RDI] = state->IntRegisterValue(X86_64_REGISTER_RDI);
|
||||||
case UD_R_RSI: return X86_64_REGISTER_RSI;
|
context->values[ZYDIS_REGISTER_R8] = state->IntRegisterValue(X86_64_REGISTER_R8);
|
||||||
case UD_R_RDI: return X86_64_REGISTER_RDI;
|
context->values[ZYDIS_REGISTER_R9] = state->IntRegisterValue(X86_64_REGISTER_R9);
|
||||||
|
context->values[ZYDIS_REGISTER_R10] = state->IntRegisterValue(X86_64_REGISTER_R10);
|
||||||
case UD_R_R8: return X86_64_REGISTER_R8;
|
context->values[ZYDIS_REGISTER_R11] = state->IntRegisterValue(X86_64_REGISTER_R11);
|
||||||
case UD_R_R9: return X86_64_REGISTER_R9;
|
context->values[ZYDIS_REGISTER_R12] = state->IntRegisterValue(X86_64_REGISTER_R12);
|
||||||
case UD_R_R10: return X86_64_REGISTER_R10;
|
context->values[ZYDIS_REGISTER_R13] = state->IntRegisterValue(X86_64_REGISTER_R13);
|
||||||
case UD_R_R11: return X86_64_REGISTER_R11;
|
context->values[ZYDIS_REGISTER_R14] = state->IntRegisterValue(X86_64_REGISTER_R14);
|
||||||
case UD_R_R12: return X86_64_REGISTER_R12;
|
context->values[ZYDIS_REGISTER_R15] = state->IntRegisterValue(X86_64_REGISTER_R15);
|
||||||
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 {
|
struct DisassemblerX8664::ZydisData {
|
||||||
|
ZydisDecoder decoder ;
|
||||||
|
ZydisFormatter formatter;
|
||||||
|
ZyanUSize offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -64,14 +56,14 @@ DisassemblerX8664::DisassemblerX8664()
|
|||||||
fAddress(0),
|
fAddress(0),
|
||||||
fCode(NULL),
|
fCode(NULL),
|
||||||
fCodeSize(0),
|
fCodeSize(0),
|
||||||
fUdisData(NULL)
|
fZydisData(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DisassemblerX8664::~DisassemblerX8664()
|
DisassemblerX8664::~DisassemblerX8664()
|
||||||
{
|
{
|
||||||
delete fUdisData;
|
delete fZydisData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -79,25 +71,33 @@ status_t
|
|||||||
DisassemblerX8664::Init(target_addr_t address, const void* code, size_t codeSize)
|
DisassemblerX8664::Init(target_addr_t address, const void* code, size_t codeSize)
|
||||||
{
|
{
|
||||||
// unset old data
|
// unset old data
|
||||||
delete fUdisData;
|
delete fZydisData;
|
||||||
fUdisData = NULL;
|
fZydisData = NULL;
|
||||||
|
|
||||||
// set new data
|
// set new data
|
||||||
fUdisData = new(std::nothrow) UdisData;
|
fZydisData = new(std::nothrow) ZydisData;
|
||||||
if (fUdisData == NULL)
|
if (fZydisData == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
fAddress = address;
|
fAddress = address;
|
||||||
fCode = (const uint8*)code;
|
fCode = (const uint8*)code;
|
||||||
fCodeSize = codeSize;
|
fCodeSize = codeSize;
|
||||||
|
|
||||||
// init udis
|
// init zydis
|
||||||
ud_init(fUdisData);
|
fZydisData->offset = 0;
|
||||||
ud_set_input_buffer(fUdisData, (unsigned char*)fCode, fCodeSize);
|
ZydisDecoderInit(&fZydisData->decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
|
||||||
ud_set_mode(fUdisData, 64);
|
ZydisFormatterInit(&fZydisData->formatter, ZYDIS_FORMATTER_STYLE_ATT);
|
||||||
ud_set_pc(fUdisData, (uint64_t)fAddress);
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE);
|
||||||
ud_set_syntax(fUdisData, UD_SYN_ATT);
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_HEX_UPPERCASE,
|
||||||
ud_set_vendor(fUdisData, UD_VENDOR_INTEL);
|
ZYAN_FALSE);
|
||||||
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_ABSOLUTE,
|
||||||
|
ZYDIS_PADDING_DISABLED);
|
||||||
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_RELATIVE,
|
||||||
|
ZYDIS_PADDING_DISABLED);
|
||||||
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_DISP_PADDING,
|
||||||
|
ZYDIS_PADDING_DISABLED);
|
||||||
|
ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_IMM_PADDING,
|
||||||
|
ZYDIS_PADDING_DISABLED);
|
||||||
// TODO: Set the correct vendor!
|
// TODO: Set the correct vendor!
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -108,20 +108,35 @@ status_t
|
|||||||
DisassemblerX8664::GetNextInstruction(BString& line, target_addr_t& _address,
|
DisassemblerX8664::GetNextInstruction(BString& line, target_addr_t& _address,
|
||||||
target_size_t& _size, bool& _breakpointAllowed)
|
target_size_t& _size, bool& _breakpointAllowed)
|
||||||
{
|
{
|
||||||
unsigned int size = ud_disassemble(fUdisData);
|
const uint8* buffer = fCode + fZydisData->offset;
|
||||||
if (size < 1)
|
ZydisDecodedInstruction instruction;
|
||||||
|
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||||
|
if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&fZydisData->decoder, buffer,
|
||||||
|
fCodeSize - fZydisData->offset, &instruction, operands))) {
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
target_addr_t address = ud_insn_off(fUdisData);
|
target_addr_t address = fAddress + fZydisData->offset;
|
||||||
|
fZydisData->offset += instruction.length;
|
||||||
|
|
||||||
char buffer[256];
|
char hexString[32];
|
||||||
snprintf(buffer, sizeof(buffer), "0x%016" B_PRIx64 ": %16.16s %s", address,
|
char* srcHex = hexString;
|
||||||
ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
|
for (ZyanUSize i = 0; i < instruction.length; i++) {
|
||||||
// TODO: Resolve symbols!
|
sprintf(srcHex, "%02" PRIx8, buffer[i]);
|
||||||
|
srcHex += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char formatted[1024];
|
||||||
|
if (ZYAN_SUCCESS(ZydisFormatterFormatInstruction(&fZydisData->formatter, &instruction, operands,
|
||||||
|
instruction.operand_count_visible, formatted, sizeof(formatted), address, NULL))) {
|
||||||
|
line.SetToFormat("0x%016" B_PRIx64 ": %16.16s %s", address, hexString, formatted);
|
||||||
|
} else {
|
||||||
|
line.SetToFormat("0x%016" B_PRIx64 ": failed-to-format", address);
|
||||||
|
}
|
||||||
|
// TODO: Resolve symbols!
|
||||||
|
|
||||||
line = buffer;
|
|
||||||
_address = address;
|
_address = address;
|
||||||
_size = size;
|
_size = instruction.length;
|
||||||
_breakpointAllowed = true;
|
_breakpointAllowed = true;
|
||||||
// TODO: Implement (rep!)!
|
// TODO: Implement (rep!)!
|
||||||
|
|
||||||
@@ -138,14 +153,19 @@ DisassemblerX8664::GetPreviousInstruction(target_addr_t nextAddress,
|
|||||||
|
|
||||||
// loop until hitting the last instruction
|
// loop until hitting the last instruction
|
||||||
while (true) {
|
while (true) {
|
||||||
target_size_t size = ud_disassemble(fUdisData);
|
const uint8* buffer = fCode + fZydisData->offset;
|
||||||
if (size < 1)
|
ZydisDecodedInstruction instruction;
|
||||||
|
if (!ZYAN_SUCCESS(ZydisDecoderDecodeInstruction(&fZydisData->decoder,
|
||||||
|
(ZydisDecoderContext*)ZYAN_NULL, buffer, fCodeSize - fZydisData->offset,
|
||||||
|
&instruction))) {
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
target_addr_t address = ud_insn_off(fUdisData);
|
fZydisData->offset += instruction.length;
|
||||||
if (address + size == nextAddress) {
|
target_addr_t address = fAddress + fZydisData->offset;
|
||||||
|
if (address == nextAddress) {
|
||||||
_address = address;
|
_address = address;
|
||||||
_size = size;
|
_size = instruction.length;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,104 +176,55 @@ status_t
|
|||||||
DisassemblerX8664::GetNextInstructionInfo(InstructionInfo& _info,
|
DisassemblerX8664::GetNextInstructionInfo(InstructionInfo& _info,
|
||||||
CpuState* state)
|
CpuState* state)
|
||||||
{
|
{
|
||||||
unsigned int size = ud_disassemble(fUdisData);
|
const uint8* buffer = fCode + fZydisData->offset;
|
||||||
if (size < 1)
|
ZydisDecodedInstruction instruction;
|
||||||
|
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||||
|
if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&fZydisData->decoder, buffer,
|
||||||
|
fCodeSize - fZydisData->offset, &instruction, operands))) {
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
target_addr_t address = ud_insn_off(fUdisData);
|
target_addr_t address = fAddress + fZydisData->offset;
|
||||||
|
fZydisData->offset += instruction.length;
|
||||||
|
|
||||||
|
char hexString[32];
|
||||||
|
char* srcHex = hexString;
|
||||||
|
for (ZyanUSize i = 0; i < instruction.length; i++) {
|
||||||
|
sprintf(srcHex, "%02" PRIx8, buffer[i]);
|
||||||
|
srcHex += 2;
|
||||||
|
}
|
||||||
|
|
||||||
instruction_type type = INSTRUCTION_TYPE_OTHER;
|
instruction_type type = INSTRUCTION_TYPE_OTHER;
|
||||||
target_addr_t targetAddress = 0;
|
target_addr_t targetAddress = 0;
|
||||||
|
if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL)
|
||||||
ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData);
|
|
||||||
if (mnemonic == UD_Icall)
|
|
||||||
type = INSTRUCTION_TYPE_SUBROUTINE_CALL;
|
type = INSTRUCTION_TYPE_SUBROUTINE_CALL;
|
||||||
else if (mnemonic == UD_Ijmp)
|
else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP)
|
||||||
type = INSTRUCTION_TYPE_JUMP;
|
type = INSTRUCTION_TYPE_JUMP;
|
||||||
if (state != NULL)
|
if (state != NULL) {
|
||||||
targetAddress = GetInstructionTargetAddress(state);
|
CpuStateX8664* x64State = dynamic_cast<CpuStateX8664*>(state);
|
||||||
|
if (x64State != NULL) {
|
||||||
|
ZydisRegisterContext registers;
|
||||||
|
CpuStateToZydisRegContext(x64State, ®isters);
|
||||||
|
ZYAN_CHECK(ZydisCalcAbsoluteAddressEx(&instruction, operands,
|
||||||
|
address, ®isters, &targetAddress));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char buffer[256];
|
char string[1024];
|
||||||
snprintf(buffer, sizeof(buffer), "0x%016" B_PRIx64 ": %16.16s %s", address,
|
int written = snprintf(string, sizeof(string), "0x%016" B_PRIx64 ": %16.16s ", address,
|
||||||
ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
|
hexString);
|
||||||
// TODO: Resolve symbols!
|
char* formatted = string + written;
|
||||||
|
if (!ZYAN_SUCCESS(ZydisFormatterFormatInstruction(&fZydisData->formatter, &instruction,
|
||||||
|
operands, instruction.operand_count_visible, formatted, sizeof(string) - written,
|
||||||
|
address, NULL))) {
|
||||||
|
snprintf(string, sizeof(string), "0x%016" B_PRIx64 ": failed-to-format", address);
|
||||||
|
}
|
||||||
|
|
||||||
if (!_info.SetTo(address, targetAddress, size, type, true, buffer))
|
// TODO: Resolve symbols!
|
||||||
|
|
||||||
|
if (!_info.SetTo(address, targetAddress, instruction.length, type, true, string))
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
target_addr_t
|
|
||||||
DisassemblerX8664::GetInstructionTargetAddress(CpuState* state) const
|
|
||||||
{
|
|
||||||
ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData);
|
|
||||||
if (mnemonic != UD_Icall && mnemonic != UD_Ijmp)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
CpuStateX8664* x64State = dynamic_cast<CpuStateX8664*>(state);
|
|
||||||
if (x64State == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
target_addr_t targetAddress = 0;
|
|
||||||
const struct ud_operand* op = ud_insn_opr(fUdisData, 0);
|
|
||||||
switch (op->type) {
|
|
||||||
case UD_OP_REG:
|
|
||||||
{
|
|
||||||
targetAddress = x64State->IntRegisterValue(
|
|
||||||
RegisterNumberFromUdisIndex(op->base));
|
|
||||||
targetAddress += op->offset;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UD_OP_MEM:
|
|
||||||
{
|
|
||||||
targetAddress = x64State->IntRegisterValue(
|
|
||||||
RegisterNumberFromUdisIndex(op->base));
|
|
||||||
targetAddress += x64State->IntRegisterValue(
|
|
||||||
RegisterNumberFromUdisIndex(op->index))
|
|
||||||
* op->scale;
|
|
||||||
off_t offset = 0;
|
|
||||||
switch (op->offset) {
|
|
||||||
case 8:
|
|
||||||
offset = op->lval.sbyte;
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
offset = op->lval.sword;
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
offset = op->lval.sdword;
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
offset = op->lval.sqword;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
targetAddress += offset;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UD_OP_JIMM:
|
|
||||||
{
|
|
||||||
targetAddress = ud_insn_off(fUdisData) + ud_insn_len(fUdisData);
|
|
||||||
if (op->size == 32)
|
|
||||||
targetAddress += op->lval.sdword;
|
|
||||||
else
|
|
||||||
targetAddress += op->lval.sqword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UD_OP_IMM:
|
|
||||||
case UD_OP_CONST:
|
|
||||||
{
|
|
||||||
if (op->size == 32)
|
|
||||||
targetAddress = op->lval.udword;
|
|
||||||
else if (op->size == 64)
|
|
||||||
targetAddress = op->lval.uqword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetAddress;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -36,16 +36,13 @@ public:
|
|||||||
CpuState* state);
|
CpuState* state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
target_addr_t GetInstructionTargetAddress(
|
struct ZydisData;
|
||||||
CpuState* state) const;
|
|
||||||
private:
|
|
||||||
struct UdisData;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
target_addr_t fAddress;
|
target_addr_t fAddress;
|
||||||
const uint8* fCode;
|
const uint8* fCode;
|
||||||
size_t fCodeSize;
|
size_t fCodeSize;
|
||||||
UdisData* fUdisData;
|
ZydisData* fZydisData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ UsePrivateHeaders shared ;
|
|||||||
UsePrivateHeaders [ FDirName debugger arch ] ;
|
UsePrivateHeaders [ FDirName debugger arch ] ;
|
||||||
UsePrivateHeaders [ FDirName debugger types ] ;
|
UsePrivateHeaders [ FDirName debugger types ] ;
|
||||||
|
|
||||||
UseHeaders [ LibraryHeaders udis86 ] ;
|
UseHeaders [ LibraryHeaders zydis ] : true ;
|
||||||
UseHeaders [ LibraryHeaders [ FDirName udis86 libudis86 ] ] ;
|
|
||||||
|
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
|
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
|
||||||
|
|
||||||
|
DEFINES += ZYDIS_DISABLE_ENCODER ;
|
||||||
|
|
||||||
MergeObject Debugger_disasm_x86_64.o
|
MergeObject Debugger_disasm_x86_64.o
|
||||||
:
|
:
|
||||||
|
|||||||
Reference in New Issue
Block a user