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
CpuStateToZydisRegContext(CpuStateX86 * state,ZydisRegisterContext * context)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
DisassemblerX86()45 DisassemblerX86::DisassemblerX86()
46 :
47 fAddress(0),
48 fCode(NULL),
49 fCodeSize(0),
50 fZydisData(NULL)
51 {
52 }
53
54
~DisassemblerX86()55 DisassemblerX86::~DisassemblerX86()
56 {
57 delete fZydisData;
58 }
59
60
61 status_t
Init(target_addr_t address,const void * code,size_t codeSize)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
GetNextInstruction(BString & line,target_addr_t & _address,target_size_t & _size,bool & _breakpointAllowed)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
GetPreviousInstruction(target_addr_t nextAddress,target_addr_t & _address,target_size_t & _size)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
GetNextInstructionInfo(InstructionInfo & _info,CpuState * state)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, ®isters);
200 ZYAN_CHECK(ZydisCalcAbsoluteAddressEx(&instruction, operands,
201 address, ®isters, &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