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