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