xref: /haiku/src/kits/debugger/arch/x86_64/disasm/DisassemblerX8664.cpp (revision 34b59fca80cb34494cf34149d8af13584bdb18e2)
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, &registers);
208*34b59fcaSJérôme Duval 			ZYAN_CHECK(ZydisCalcAbsoluteAddressEx(&instruction, operands,
209*34b59fcaSJérôme Duval 				address, &registers, &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