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