xref: /haiku/src/kits/debugger/arch/x86_64/disasm/DisassemblerX8664.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
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 "udis86.h"
14 
15 #include <OS.h>
16 
17 
18 #include "CpuStateX8664.h"
19 #include "InstructionInfo.h"
20 
21 
22 static uint8 RegisterNumberFromUdisIndex(int32 udisIndex)
23 {
24 	switch (udisIndex) {
25 		case UD_R_RIP: return X86_64_REGISTER_RIP;
26 		case UD_R_RSP: return X86_64_REGISTER_RSP;
27 		case UD_R_RBP: return X86_64_REGISTER_RBP;
28 
29 		case UD_R_RAX: return X86_64_REGISTER_RAX;
30 		case UD_R_RBX: return X86_64_REGISTER_RBX;
31 		case UD_R_RCX: return X86_64_REGISTER_RCX;
32 		case UD_R_RDX: return X86_64_REGISTER_RDX;
33 
34 		case UD_R_RSI: return X86_64_REGISTER_RSI;
35 		case UD_R_RDI: return X86_64_REGISTER_RDI;
36 
37 		case UD_R_R8: return X86_64_REGISTER_R8;
38 		case UD_R_R9: return X86_64_REGISTER_R9;
39 		case UD_R_R10: return X86_64_REGISTER_R10;
40 		case UD_R_R11: return X86_64_REGISTER_R11;
41 		case UD_R_R12: return X86_64_REGISTER_R12;
42 		case UD_R_R13: return X86_64_REGISTER_R13;
43 		case UD_R_R14: return X86_64_REGISTER_R14;
44 		case UD_R_R15: return X86_64_REGISTER_R15;
45 
46 		case UD_R_CS: return X86_64_REGISTER_CS;
47 		case UD_R_DS: return X86_64_REGISTER_DS;
48 		case UD_R_ES: return X86_64_REGISTER_ES;
49 		case UD_R_FS: return X86_64_REGISTER_FS;
50 		case UD_R_GS: return X86_64_REGISTER_GS;
51 		case UD_R_SS: return X86_64_REGISTER_SS;
52 	}
53 
54 	return X86_64_INT_REGISTER_END;
55 }
56 
57 
58 struct DisassemblerX8664::UdisData : ud_t {
59 };
60 
61 
62 DisassemblerX8664::DisassemblerX8664()
63 	:
64 	fAddress(0),
65 	fCode(NULL),
66 	fCodeSize(0),
67 	fUdisData(NULL)
68 {
69 }
70 
71 
72 DisassemblerX8664::~DisassemblerX8664()
73 {
74 	delete fUdisData;
75 }
76 
77 
78 status_t
79 DisassemblerX8664::Init(target_addr_t address, const void* code, size_t codeSize)
80 {
81 	// unset old data
82 	delete fUdisData;
83 	fUdisData = NULL;
84 
85 	// set new data
86 	fUdisData = new(std::nothrow) UdisData;
87 	if (fUdisData == NULL)
88 		return B_NO_MEMORY;
89 
90 	fAddress = address;
91 	fCode = (const uint8*)code;
92 	fCodeSize = codeSize;
93 
94 	// init udis
95 	ud_init(fUdisData);
96 	ud_set_input_buffer(fUdisData, (unsigned char*)fCode, fCodeSize);
97 	ud_set_mode(fUdisData, 64);
98 	ud_set_pc(fUdisData, (uint64_t)fAddress);
99 	ud_set_syntax(fUdisData, UD_SYN_ATT);
100 	ud_set_vendor(fUdisData, UD_VENDOR_INTEL);
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 	unsigned int size = ud_disassemble(fUdisData);
112 	if (size < 1)
113 		return B_ENTRY_NOT_FOUND;
114 
115 	target_addr_t address = ud_insn_off(fUdisData);
116 
117 	char buffer[256];
118 	snprintf(buffer, sizeof(buffer), "0x%016" B_PRIx64 ": %16.16s  %s", address,
119 		ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
120 			// TODO: Resolve symbols!
121 
122 	line = buffer;
123 	_address = address;
124 	_size = size;
125 	_breakpointAllowed = true;
126 		// TODO: Implement (rep!)!
127 
128 	return B_OK;
129 }
130 
131 
132 status_t
133 DisassemblerX8664::GetPreviousInstruction(target_addr_t nextAddress,
134 	target_addr_t& _address, target_size_t& _size)
135 {
136 	if (nextAddress < fAddress || nextAddress > fAddress + fCodeSize)
137 		return B_BAD_VALUE;
138 
139 	// loop until hitting the last instruction
140 	while (true) {
141 		target_size_t size = ud_disassemble(fUdisData);
142 		if (size < 1)
143 			return B_ENTRY_NOT_FOUND;
144 
145 		target_addr_t address = ud_insn_off(fUdisData);
146 		if (address + size == nextAddress) {
147 			_address = address;
148 			_size = size;
149 			return B_OK;
150 		}
151 	}
152 }
153 
154 
155 status_t
156 DisassemblerX8664::GetNextInstructionInfo(InstructionInfo& _info,
157 	CpuState* state)
158 {
159 	unsigned int size = ud_disassemble(fUdisData);
160 	if (size < 1)
161 		return B_ENTRY_NOT_FOUND;
162 
163 	target_addr_t address = ud_insn_off(fUdisData);
164 
165 	instruction_type type = INSTRUCTION_TYPE_OTHER;
166 	target_addr_t targetAddress = 0;
167 
168 	ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData);
169 	if (mnemonic == UD_Icall)
170 		type = INSTRUCTION_TYPE_SUBROUTINE_CALL;
171 	else if (mnemonic == UD_Ijmp)
172 		type = INSTRUCTION_TYPE_JUMP;
173 	if (state != NULL)
174 		targetAddress = GetInstructionTargetAddress(state);
175 
176 	char buffer[256];
177 	snprintf(buffer, sizeof(buffer), "0x%016" B_PRIx64 ": %16.16s  %s", address,
178 		ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
179 			// TODO: Resolve symbols!
180 
181 	if (!_info.SetTo(address, targetAddress, size, type, true, buffer))
182 		return B_NO_MEMORY;
183 
184 	return B_OK;
185 }
186 
187 
188 target_addr_t
189 DisassemblerX8664::GetInstructionTargetAddress(CpuState* state) const
190 {
191 	ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData);
192 	if (mnemonic != UD_Icall && mnemonic != UD_Ijmp)
193 		return 0;
194 
195 	CpuStateX8664* x64State = dynamic_cast<CpuStateX8664*>(state);
196 	if (x64State == NULL)
197 		return 0;
198 
199 	target_addr_t targetAddress = 0;
200 	const struct ud_operand* op = ud_insn_opr(fUdisData, 0);
201 	switch (op->type) {
202 		case UD_OP_REG:
203 		{
204 			targetAddress = x64State->IntRegisterValue(
205 				RegisterNumberFromUdisIndex(op->base));
206 			targetAddress += op->offset;
207 		}
208 		break;
209 		case UD_OP_MEM:
210 		{
211 			targetAddress = x64State->IntRegisterValue(
212 				RegisterNumberFromUdisIndex(op->base));
213 			targetAddress += x64State->IntRegisterValue(
214 				RegisterNumberFromUdisIndex(op->index))
215 				* op->scale;
216 			off_t offset = 0;
217 			switch (op->offset) {
218 				case 8:
219 					offset = op->lval.sbyte;
220 					break;
221 				case 16:
222 					offset = op->lval.sword;
223 					break;
224 				case 32:
225 					offset = op->lval.sdword;
226 					break;
227 				case 64:
228 					offset = op->lval.sqword;
229 					break;
230 			}
231 			targetAddress += offset;
232 		}
233 		break;
234 		case UD_OP_JIMM:
235 		{
236 			targetAddress = ud_insn_off(fUdisData) + ud_insn_len(fUdisData);
237 			if (op->size == 32)
238 				targetAddress += op->lval.sdword;
239 			else
240 				targetAddress += op->lval.sqword;
241 		}
242 		break;
243 
244 		case UD_OP_IMM:
245 		case UD_OP_CONST:
246 		{
247 			if (op->size == 32)
248 				targetAddress = op->lval.udword;
249 			else if (op->size == 64)
250 				targetAddress = op->lval.uqword;
251 		}
252 		break;
253 
254 		default:
255 		break;
256 	}
257 
258 	return targetAddress;
259 }
260