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