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