xref: /haiku/src/kits/debugger/arch/x86/disasm/DisassemblerX86.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
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 "udis86.h"
13 
14 #include <OS.h>
15 
16 #include "CpuStateX86.h"
17 #include "InstructionInfo.h"
18 
19 
20 static uint8 RegisterNumberFromUdisIndex(int32 udisIndex)
21 {
22 	switch (udisIndex) {
23 		case UD_R_RIP: return X86_REGISTER_EIP;
24 		case UD_R_ESP: return X86_REGISTER_ESP;
25 		case UD_R_EBP: return X86_REGISTER_EBP;
26 
27 		case UD_R_EAX: return X86_REGISTER_EAX;
28 		case UD_R_EBX: return X86_REGISTER_EBX;
29 		case UD_R_ECX: return X86_REGISTER_ECX;
30 		case UD_R_EDX: return X86_REGISTER_EDX;
31 
32 		case UD_R_ESI: return X86_REGISTER_ESI;
33 		case UD_R_EDI: return X86_REGISTER_EDI;
34 
35 		case UD_R_CS: return X86_REGISTER_CS;
36 		case UD_R_DS: return X86_REGISTER_DS;
37 		case UD_R_ES: return X86_REGISTER_ES;
38 		case UD_R_FS: return X86_REGISTER_FS;
39 		case UD_R_GS: return X86_REGISTER_GS;
40 		case UD_R_SS: return X86_REGISTER_SS;
41 	}
42 
43 	return X86_INT_REGISTER_END;
44 }
45 
46 
47 struct DisassemblerX86::UdisData : ud_t {
48 };
49 
50 
51 DisassemblerX86::DisassemblerX86()
52 	:
53 	fAddress(0),
54 	fCode(NULL),
55 	fCodeSize(0),
56 	fUdisData(NULL)
57 {
58 }
59 
60 
61 DisassemblerX86::~DisassemblerX86()
62 {
63 	delete fUdisData;
64 }
65 
66 
67 status_t
68 DisassemblerX86::Init(target_addr_t address, const void* code, size_t codeSize)
69 {
70 	// unset old data
71 	delete fUdisData;
72 	fUdisData = NULL;
73 
74 	// set new data
75 	fUdisData = new(std::nothrow) UdisData;
76 	if (fUdisData == NULL)
77 		return B_NO_MEMORY;
78 
79 	fAddress = address;
80 	fCode = (const uint8*)code;
81 	fCodeSize = codeSize;
82 
83 	// init udis
84 	ud_init(fUdisData);
85 	ud_set_input_buffer(fUdisData, (unsigned char*)fCode, fCodeSize);
86 	ud_set_mode(fUdisData, 32);
87 	ud_set_pc(fUdisData, (uint64_t)fAddress);
88 	ud_set_syntax(fUdisData, UD_SYN_ATT);
89 	ud_set_vendor(fUdisData, UD_VENDOR_INTEL);
90 		// TODO: Set the correct vendor!
91 
92 	return B_OK;
93 }
94 
95 
96 status_t
97 DisassemblerX86::GetNextInstruction(BString& line, target_addr_t& _address,
98 	target_size_t& _size, bool& _breakpointAllowed)
99 {
100 	unsigned int size = ud_disassemble(fUdisData);
101 	if (size < 1)
102 		return B_ENTRY_NOT_FOUND;
103 
104 	uint32 address = (uint32)ud_insn_off(fUdisData);
105 
106 	char buffer[256];
107 	snprintf(buffer, sizeof(buffer), "0x%08" B_PRIx32 ": %16.16s  %s", address,
108 		ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
109 			// TODO: Resolve symbols!
110 
111 	line = buffer;
112 	_address = address;
113 	_size = size;
114 	_breakpointAllowed = true;
115 		// TODO: Implement (rep!)!
116 
117 	return B_OK;
118 }
119 
120 
121 status_t
122 DisassemblerX86::GetPreviousInstruction(target_addr_t nextAddress,
123 	target_addr_t& _address, target_size_t& _size)
124 {
125 	if (nextAddress < fAddress || nextAddress > fAddress + fCodeSize)
126 		return B_BAD_VALUE;
127 
128 	// loop until hitting the last instruction
129 	while (true) {
130 		unsigned int size = ud_disassemble(fUdisData);
131 		if (size < 1)
132 			return B_ENTRY_NOT_FOUND;
133 
134 		uint32 address = (uint32)ud_insn_off(fUdisData);
135 		if (address + size == nextAddress) {
136 			_address = address;
137 			_size = size;
138 			return B_OK;
139 		}
140 	}
141 }
142 
143 
144 status_t
145 DisassemblerX86::GetNextInstructionInfo(InstructionInfo& _info,
146 	CpuState* state)
147 {
148 	unsigned int size = ud_disassemble(fUdisData);
149 	if (size < 1)
150 		return B_ENTRY_NOT_FOUND;
151 
152 	uint32 address = (uint32)ud_insn_off(fUdisData);
153 
154 	instruction_type type = INSTRUCTION_TYPE_OTHER;
155 	target_addr_t targetAddress = 0;
156 
157 	ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData);
158 	if (mnemonic == UD_Icall)
159 		type = INSTRUCTION_TYPE_SUBROUTINE_CALL;
160 	else if (mnemonic == UD_Ijmp)
161 		type = INSTRUCTION_TYPE_JUMP;
162 	if (state != NULL)
163 		targetAddress = GetInstructionTargetAddress(state);
164 
165 	char buffer[256];
166 	snprintf(buffer, sizeof(buffer), "0x%08" B_PRIx32 ": %16.16s  %s", address,
167 		ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
168 			// TODO: Resolve symbols!
169 
170 	if (!_info.SetTo(address, targetAddress, size, type, true, buffer))
171 		return B_NO_MEMORY;
172 
173 	return B_OK;
174 }
175 
176 
177 target_addr_t
178 DisassemblerX86::GetInstructionTargetAddress(CpuState* state) const
179 {
180 	ud_mnemonic_code mnemonic = ud_insn_mnemonic(fUdisData);
181 	if (mnemonic != UD_Icall && mnemonic != UD_Ijmp)
182 		return 0;
183 
184 	CpuStateX86* x86State = dynamic_cast<CpuStateX86*>(state);
185 	if (x86State == NULL)
186 		return 0;
187 
188 	target_addr_t targetAddress = 0;
189 	const struct ud_operand* op = ud_insn_opr(fUdisData, 0);
190 	switch (op->type) {
191 		case UD_OP_REG:
192 		{
193 			targetAddress = x86State->IntRegisterValue(
194 				RegisterNumberFromUdisIndex(op->base));
195 			targetAddress += op->offset;
196 		}
197 		break;
198 		case UD_OP_MEM:
199 		{
200 			targetAddress = x86State->IntRegisterValue(
201 				RegisterNumberFromUdisIndex(op->base));
202 			targetAddress += x86State->IntRegisterValue(
203 				RegisterNumberFromUdisIndex(op->index))
204 				* op->scale;
205 			if (op->offset != 0)
206 				targetAddress += op->lval.sdword;
207 		}
208 		break;
209 		case UD_OP_JIMM:
210 		{
211 			targetAddress = ud_insn_off(fUdisData)
212 				+ op->lval.sdword + ud_insn_len(fUdisData);
213 		}
214 		break;
215 
216 		case UD_OP_IMM:
217 		case UD_OP_CONST:
218 		{
219 			targetAddress = op->lval.udword;
220 		}
221 		break;
222 
223 		default:
224 		break;
225 	}
226 
227 	return targetAddress;
228 }
229