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