1fce4895dSRene Gollent /*
2fce4895dSRene Gollent * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
3fce4895dSRene Gollent * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
4fce4895dSRene Gollent * Copyright 2008, François Revol, revol@free.fr
5fce4895dSRene Gollent * Copyright 2016, Rene Gollent, rene@gollent.com.
6fce4895dSRene Gollent * Distributed under the terms of the MIT License.
7fce4895dSRene Gollent */
8fce4895dSRene Gollent
9fce4895dSRene Gollent #include "DisassemblerX8664.h"
10fce4895dSRene Gollent
11fce4895dSRene Gollent #include <new>
12fce4895dSRene Gollent
13*34b59fcaSJérôme Duval #include "Zycore/Format.h"
14*34b59fcaSJérôme Duval #include "Zydis/Zydis.h"
15fce4895dSRene Gollent
16fce4895dSRene Gollent #include <OS.h>
17fce4895dSRene Gollent
18fce4895dSRene Gollent
19fce4895dSRene Gollent #include "CpuStateX8664.h"
20fce4895dSRene Gollent #include "InstructionInfo.h"
21fce4895dSRene Gollent
22fce4895dSRene Gollent
23*34b59fcaSJérôme Duval void
CpuStateToZydisRegContext(CpuStateX8664 * state,ZydisRegisterContext * context)24*34b59fcaSJérôme Duval CpuStateToZydisRegContext(CpuStateX8664* state, ZydisRegisterContext* context)
25fce4895dSRene Gollent {
26*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_RAX] = state->IntRegisterValue(X86_64_REGISTER_RAX);
27*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_RSP] = state->IntRegisterValue(X86_64_REGISTER_RSP);
28*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_RIP] = state->IntRegisterValue(X86_64_REGISTER_RIP);
29*34b59fcaSJérôme Duval // context->values[ZYDIS_REGISTER_RFLAGS] = eflags;
30*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_RCX] = state->IntRegisterValue(X86_64_REGISTER_RCX);
31*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_RDX] = state->IntRegisterValue(X86_64_REGISTER_RDX);
32*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_RBX] = state->IntRegisterValue(X86_64_REGISTER_RBX);
33*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_RBP] = state->IntRegisterValue(X86_64_REGISTER_RBP);
34*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_RSI] = state->IntRegisterValue(X86_64_REGISTER_RSI);
35*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_RDI] = state->IntRegisterValue(X86_64_REGISTER_RDI);
36*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_R8] = state->IntRegisterValue(X86_64_REGISTER_R8);
37*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_R9] = state->IntRegisterValue(X86_64_REGISTER_R9);
38*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_R10] = state->IntRegisterValue(X86_64_REGISTER_R10);
39*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_R11] = state->IntRegisterValue(X86_64_REGISTER_R11);
40*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_R12] = state->IntRegisterValue(X86_64_REGISTER_R12);
41*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_R13] = state->IntRegisterValue(X86_64_REGISTER_R13);
42*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_R14] = state->IntRegisterValue(X86_64_REGISTER_R14);
43*34b59fcaSJérôme Duval context->values[ZYDIS_REGISTER_R15] = state->IntRegisterValue(X86_64_REGISTER_R15);
44fce4895dSRene Gollent }
45fce4895dSRene Gollent
46fce4895dSRene Gollent
47*34b59fcaSJérôme Duval struct DisassemblerX8664::ZydisData {
48*34b59fcaSJérôme Duval ZydisDecoder decoder ;
49*34b59fcaSJérôme Duval ZydisFormatter formatter;
50*34b59fcaSJérôme Duval ZyanUSize offset;
51fce4895dSRene Gollent };
52fce4895dSRene Gollent
53fce4895dSRene Gollent
DisassemblerX8664()54fce4895dSRene Gollent DisassemblerX8664::DisassemblerX8664()
55fce4895dSRene Gollent :
56fce4895dSRene Gollent fAddress(0),
57fce4895dSRene Gollent fCode(NULL),
58fce4895dSRene Gollent fCodeSize(0),
59*34b59fcaSJérôme Duval fZydisData(NULL)
60fce4895dSRene Gollent {
61fce4895dSRene Gollent }
62fce4895dSRene Gollent
63fce4895dSRene Gollent
~DisassemblerX8664()64fce4895dSRene Gollent DisassemblerX8664::~DisassemblerX8664()
65fce4895dSRene Gollent {
66*34b59fcaSJérôme Duval delete fZydisData;
67fce4895dSRene Gollent }
68fce4895dSRene Gollent
69fce4895dSRene Gollent
70fce4895dSRene Gollent status_t
Init(target_addr_t address,const void * code,size_t codeSize)71fce4895dSRene Gollent DisassemblerX8664::Init(target_addr_t address, const void* code, size_t codeSize)
72fce4895dSRene Gollent {
73fce4895dSRene Gollent // unset old data
74*34b59fcaSJérôme Duval delete fZydisData;
75*34b59fcaSJérôme Duval fZydisData = NULL;
76fce4895dSRene Gollent
77fce4895dSRene Gollent // set new data
78*34b59fcaSJérôme Duval fZydisData = new(std::nothrow) ZydisData;
79*34b59fcaSJérôme Duval if (fZydisData == NULL)
80fce4895dSRene Gollent return B_NO_MEMORY;
81fce4895dSRene Gollent
82fce4895dSRene Gollent fAddress = address;
83fce4895dSRene Gollent fCode = (const uint8*)code;
84fce4895dSRene Gollent fCodeSize = codeSize;
85fce4895dSRene Gollent
86*34b59fcaSJérôme Duval // init zydis
87*34b59fcaSJérôme Duval fZydisData->offset = 0;
88*34b59fcaSJérôme Duval ZydisDecoderInit(&fZydisData->decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
89*34b59fcaSJérôme Duval ZydisFormatterInit(&fZydisData->formatter, ZYDIS_FORMATTER_STYLE_ATT);
90*34b59fcaSJérôme Duval ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_FORCE_SIZE, ZYAN_TRUE);
91*34b59fcaSJérôme Duval ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_HEX_UPPERCASE,
92*34b59fcaSJérôme Duval ZYAN_FALSE);
93*34b59fcaSJérôme Duval ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_ABSOLUTE,
94*34b59fcaSJérôme Duval ZYDIS_PADDING_DISABLED);
95*34b59fcaSJérôme Duval ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_ADDR_PADDING_RELATIVE,
96*34b59fcaSJérôme Duval ZYDIS_PADDING_DISABLED);
97*34b59fcaSJérôme Duval ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_DISP_PADDING,
98*34b59fcaSJérôme Duval ZYDIS_PADDING_DISABLED);
99*34b59fcaSJérôme Duval ZydisFormatterSetProperty(&fZydisData->formatter, ZYDIS_FORMATTER_PROP_IMM_PADDING,
100*34b59fcaSJérôme Duval ZYDIS_PADDING_DISABLED);
101fce4895dSRene Gollent // TODO: Set the correct vendor!
102fce4895dSRene Gollent
103fce4895dSRene Gollent return B_OK;
104fce4895dSRene Gollent }
105fce4895dSRene Gollent
106fce4895dSRene Gollent
107fce4895dSRene Gollent status_t
GetNextInstruction(BString & line,target_addr_t & _address,target_size_t & _size,bool & _breakpointAllowed)108fce4895dSRene Gollent DisassemblerX8664::GetNextInstruction(BString& line, target_addr_t& _address,
109fce4895dSRene Gollent target_size_t& _size, bool& _breakpointAllowed)
110fce4895dSRene Gollent {
111*34b59fcaSJérôme Duval const uint8* buffer = fCode + fZydisData->offset;
112*34b59fcaSJérôme Duval ZydisDecodedInstruction instruction;
113*34b59fcaSJérôme Duval ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
114*34b59fcaSJérôme Duval if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&fZydisData->decoder, buffer,
115*34b59fcaSJérôme Duval fCodeSize - fZydisData->offset, &instruction, operands))) {
116fce4895dSRene Gollent return B_ENTRY_NOT_FOUND;
117*34b59fcaSJérôme Duval }
118fce4895dSRene Gollent
119*34b59fcaSJérôme Duval target_addr_t address = fAddress + fZydisData->offset;
120*34b59fcaSJérôme Duval fZydisData->offset += instruction.length;
121fce4895dSRene Gollent
122*34b59fcaSJérôme Duval char hexString[32];
123*34b59fcaSJérôme Duval char* srcHex = hexString;
124*34b59fcaSJérôme Duval for (ZyanUSize i = 0; i < instruction.length; i++) {
125*34b59fcaSJérôme Duval sprintf(srcHex, "%02" PRIx8, buffer[i]);
126*34b59fcaSJérôme Duval srcHex += 2;
127*34b59fcaSJérôme Duval }
128*34b59fcaSJérôme Duval
129*34b59fcaSJérôme Duval char formatted[1024];
130*34b59fcaSJérôme Duval if (ZYAN_SUCCESS(ZydisFormatterFormatInstruction(&fZydisData->formatter, &instruction, operands,
131*34b59fcaSJérôme Duval instruction.operand_count_visible, formatted, sizeof(formatted), address, NULL))) {
132*34b59fcaSJérôme Duval line.SetToFormat("0x%016" B_PRIx64 ": %16.16s %s", address, hexString, formatted);
133*34b59fcaSJérôme Duval } else {
134*34b59fcaSJérôme Duval line.SetToFormat("0x%016" B_PRIx64 ": failed-to-format", address);
135*34b59fcaSJérôme Duval }
136fce4895dSRene Gollent // TODO: Resolve symbols!
137fce4895dSRene Gollent
138fce4895dSRene Gollent _address = address;
139*34b59fcaSJérôme Duval _size = instruction.length;
140fce4895dSRene Gollent _breakpointAllowed = true;
141fce4895dSRene Gollent // TODO: Implement (rep!)!
142fce4895dSRene Gollent
143fce4895dSRene Gollent return B_OK;
144fce4895dSRene Gollent }
145fce4895dSRene Gollent
146fce4895dSRene Gollent
147fce4895dSRene Gollent status_t
GetPreviousInstruction(target_addr_t nextAddress,target_addr_t & _address,target_size_t & _size)148fce4895dSRene Gollent DisassemblerX8664::GetPreviousInstruction(target_addr_t nextAddress,
149fce4895dSRene Gollent target_addr_t& _address, target_size_t& _size)
150fce4895dSRene Gollent {
151fce4895dSRene Gollent if (nextAddress < fAddress || nextAddress > fAddress + fCodeSize)
152fce4895dSRene Gollent return B_BAD_VALUE;
153fce4895dSRene Gollent
154fce4895dSRene Gollent // loop until hitting the last instruction
155fce4895dSRene Gollent while (true) {
156*34b59fcaSJérôme Duval const uint8* buffer = fCode + fZydisData->offset;
157*34b59fcaSJérôme Duval ZydisDecodedInstruction instruction;
158*34b59fcaSJérôme Duval if (!ZYAN_SUCCESS(ZydisDecoderDecodeInstruction(&fZydisData->decoder,
159*34b59fcaSJérôme Duval (ZydisDecoderContext*)ZYAN_NULL, buffer, fCodeSize - fZydisData->offset,
160*34b59fcaSJérôme Duval &instruction))) {
161fce4895dSRene Gollent return B_ENTRY_NOT_FOUND;
162*34b59fcaSJérôme Duval }
163fce4895dSRene Gollent
164*34b59fcaSJérôme Duval fZydisData->offset += instruction.length;
165*34b59fcaSJérôme Duval target_addr_t address = fAddress + fZydisData->offset;
166*34b59fcaSJérôme Duval if (address == nextAddress) {
167fce4895dSRene Gollent _address = address;
168*34b59fcaSJérôme Duval _size = instruction.length;
169fce4895dSRene Gollent return B_OK;
170fce4895dSRene Gollent }
171fce4895dSRene Gollent }
172fce4895dSRene Gollent }
173fce4895dSRene Gollent
174fce4895dSRene Gollent
175fce4895dSRene Gollent status_t
GetNextInstructionInfo(InstructionInfo & _info,CpuState * state)176fce4895dSRene Gollent DisassemblerX8664::GetNextInstructionInfo(InstructionInfo& _info,
177fce4895dSRene Gollent CpuState* state)
178fce4895dSRene Gollent {
179*34b59fcaSJérôme Duval const uint8* buffer = fCode + fZydisData->offset;
180*34b59fcaSJérôme Duval ZydisDecodedInstruction instruction;
181*34b59fcaSJérôme Duval ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
182*34b59fcaSJérôme Duval if (!ZYAN_SUCCESS(ZydisDecoderDecodeFull(&fZydisData->decoder, buffer,
183*34b59fcaSJérôme Duval fCodeSize - fZydisData->offset, &instruction, operands))) {
184fce4895dSRene Gollent return B_ENTRY_NOT_FOUND;
185*34b59fcaSJérôme Duval }
186fce4895dSRene Gollent
187*34b59fcaSJérôme Duval target_addr_t address = fAddress + fZydisData->offset;
188*34b59fcaSJérôme Duval fZydisData->offset += instruction.length;
189*34b59fcaSJérôme Duval
190*34b59fcaSJérôme Duval char hexString[32];
191*34b59fcaSJérôme Duval char* srcHex = hexString;
192*34b59fcaSJérôme Duval for (ZyanUSize i = 0; i < instruction.length; i++) {
193*34b59fcaSJérôme Duval sprintf(srcHex, "%02" PRIx8, buffer[i]);
194*34b59fcaSJérôme Duval srcHex += 2;
195*34b59fcaSJérôme Duval }
196fce4895dSRene Gollent
197fce4895dSRene Gollent instruction_type type = INSTRUCTION_TYPE_OTHER;
198fce4895dSRene Gollent target_addr_t targetAddress = 0;
199*34b59fcaSJérôme Duval if (instruction.mnemonic == ZYDIS_MNEMONIC_CALL)
200fce4895dSRene Gollent type = INSTRUCTION_TYPE_SUBROUTINE_CALL;
201*34b59fcaSJérôme Duval else if (instruction.mnemonic == ZYDIS_MNEMONIC_JMP)
202fce4895dSRene Gollent type = INSTRUCTION_TYPE_JUMP;
203*34b59fcaSJérôme Duval if (state != NULL) {
204*34b59fcaSJérôme Duval CpuStateX8664* x64State = dynamic_cast<CpuStateX8664*>(state);
205*34b59fcaSJérôme Duval if (x64State != NULL) {
206*34b59fcaSJérôme Duval ZydisRegisterContext registers;
207*34b59fcaSJérôme Duval CpuStateToZydisRegContext(x64State, ®isters);
208*34b59fcaSJérôme Duval ZYAN_CHECK(ZydisCalcAbsoluteAddressEx(&instruction, operands,
209*34b59fcaSJérôme Duval address, ®isters, &targetAddress));
210*34b59fcaSJérôme Duval }
211*34b59fcaSJérôme Duval }
212fce4895dSRene Gollent
213*34b59fcaSJérôme Duval char string[1024];
214*34b59fcaSJérôme Duval int written = snprintf(string, sizeof(string), "0x%016" B_PRIx64 ": %16.16s ", address,
215*34b59fcaSJérôme Duval hexString);
216*34b59fcaSJérôme Duval char* formatted = string + written;
217*34b59fcaSJérôme Duval if (!ZYAN_SUCCESS(ZydisFormatterFormatInstruction(&fZydisData->formatter, &instruction,
218*34b59fcaSJérôme Duval operands, instruction.operand_count_visible, formatted, sizeof(string) - written,
219*34b59fcaSJérôme Duval address, NULL))) {
220*34b59fcaSJérôme Duval snprintf(string, sizeof(string), "0x%016" B_PRIx64 ": failed-to-format", address);
221*34b59fcaSJérôme Duval }
222*34b59fcaSJérôme Duval
223fce4895dSRene Gollent // TODO: Resolve symbols!
224fce4895dSRene Gollent
225*34b59fcaSJérôme Duval if (!_info.SetTo(address, targetAddress, instruction.length, type, true, string))
226fce4895dSRene Gollent return B_NO_MEMORY;
227fce4895dSRene Gollent
228fce4895dSRene Gollent return B_OK;
229fce4895dSRene Gollent }
230fce4895dSRene Gollent
231