1 #include "views/view_disassembler.hpp" 2 3 #include <hex/providers/provider.hpp> 4 #include <hex/helpers/utils.hpp> 5 6 #include <cstring> 7 8 using namespace std::literals::string_literals; 9 10 namespace hex { 11 ViewDisassembler()12 ViewDisassembler::ViewDisassembler() : View("hex.view.disassembler.name"_lang) { 13 View::subscribeEvent(Events::DataChanged, [this](auto){ 14 this->m_shouldInvalidate = true; 15 }); 16 17 View::subscribeEvent(Events::RegionSelected, [this](auto userData) { 18 auto region = std::any_cast<Region>(userData); 19 20 if (this->m_shouldMatchSelection) { 21 this->m_codeRegion[0] = region.address; 22 this->m_codeRegion[1] = region.address + region.size - 1; 23 } 24 }); 25 } 26 ~ViewDisassembler()27 ViewDisassembler::~ViewDisassembler() { 28 View::unsubscribeEvent(Events::DataChanged); 29 View::unsubscribeEvent(Events::RegionSelected); 30 } 31 drawContent()32 void ViewDisassembler::drawContent() { 33 if (this->m_shouldInvalidate) { 34 this->m_disassembly.clear(); 35 36 csh capstoneHandle; 37 cs_insn *instructions = nullptr; 38 39 cs_mode mode = cs_mode(this->m_modeBasicARM | this->m_modeExtraARM | this->m_modeBasicMIPS | this->m_modeBasicX86 | this->m_modeBasicPPC); 40 41 if (this->m_littleEndianMode) 42 mode = cs_mode(mode | CS_MODE_LITTLE_ENDIAN); 43 else 44 mode = cs_mode(mode | CS_MODE_BIG_ENDIAN); 45 46 if (this->m_micoMode) 47 mode = cs_mode(mode | CS_MODE_MICRO); 48 49 if (this->m_sparcV9Mode) 50 mode = cs_mode(mode | CS_MODE_V9); 51 52 if (cs_open(Disassembler::toCapstoneArchictecture(this->m_architecture), mode, &capstoneHandle) == CS_ERR_OK) { 53 54 auto provider = SharedData::currentProvider; 55 std::vector<u8> buffer(2048, 0x00); 56 for (u64 address = 0; address < (this->m_codeRegion[1] - this->m_codeRegion[0] + 1); address += 2048) { 57 size_t bufferSize = std::min(u64(2048), (this->m_codeRegion[1] - this->m_codeRegion[0] + 1) - address); 58 provider->read(this->m_codeRegion[0] + address, buffer.data(), bufferSize); 59 60 size_t instructionCount = cs_disasm(capstoneHandle, buffer.data(), bufferSize, this->m_baseAddress + address, 0, &instructions); 61 62 if (instructionCount == 0) 63 break; 64 65 u64 usedBytes = 0; 66 for (u32 instr = 0; instr < instructionCount; instr++) { 67 Disassembly disassembly = { 0 }; 68 disassembly.address = instructions[instr].address; 69 disassembly.offset = this->m_codeRegion[0] + address + usedBytes; 70 disassembly.size = instructions[instr].size; 71 disassembly.mnemonic = instructions[instr].mnemonic; 72 disassembly.operators = instructions[instr].op_str; 73 74 for (u8 i = 0; i < instructions[instr].size; i++) 75 disassembly.bytes += hex::format("%02X ", instructions[instr].bytes[i]); 76 disassembly.bytes.pop_back(); 77 78 this->m_disassembly.push_back(disassembly); 79 80 usedBytes += instructions[instr].size; 81 } 82 83 if (instructionCount < bufferSize) 84 address -= (bufferSize - usedBytes); 85 86 cs_free(instructions, instructionCount); 87 } 88 89 cs_close(&capstoneHandle); 90 } 91 92 this->m_shouldInvalidate = false; 93 } 94 95 96 if (ImGui::Begin("hex.view.disassembler.name"_lang, &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) { 97 98 auto provider = SharedData::currentProvider; 99 if (provider != nullptr && provider->isReadable()) { 100 ImGui::TextUnformatted("hex.view.disassembler.position"_lang); 101 ImGui::Separator(); 102 103 ImGui::InputScalar("hex.view.disassembler.base"_lang, ImGuiDataType_U64, &this->m_baseAddress, nullptr, nullptr, "%08llX", ImGuiInputTextFlags_CharsHexadecimal); 104 ImGui::InputScalarN("hex.view.disassembler.region"_lang, ImGuiDataType_U64, this->m_codeRegion, 2, nullptr, nullptr, "%08llX", ImGuiInputTextFlags_CharsHexadecimal); 105 ImGui::Checkbox("hex.common.match_selection"_lang, &this->m_shouldMatchSelection); 106 107 ImGui::NewLine(); 108 ImGui::TextUnformatted("hex.view.disassembler.settings.header"_lang); 109 ImGui::Separator(); 110 111 ImGui::Combo("hex.view.disassembler.arch"_lang, reinterpret_cast<int*>(&this->m_architecture), Disassembler::ArchitectureNames, Disassembler::getArchitectureSupportedCount()); 112 113 114 if (ImGui::BeginChild("modes", ImVec2(0, 100), true)) { 115 116 if (ImGui::RadioButton("hex.common.little_endian"_lang, this->m_littleEndianMode)) 117 this->m_littleEndianMode = true; 118 ImGui::SameLine(); 119 if (ImGui::RadioButton("hex.common.big_endian"_lang, !this->m_littleEndianMode)) 120 this->m_littleEndianMode = false; 121 122 ImGui::NewLine(); 123 124 switch (this->m_architecture) { 125 case Architecture::ARM: 126 this->m_modeBasicMIPS = cs_mode(0); 127 this->m_modeBasicX86 = cs_mode(0); 128 this->m_modeBasicPPC = cs_mode(0); 129 this->m_micoMode = false; 130 this->m_sparcV9Mode = false; 131 132 if (this->m_modeBasicARM == cs_mode(0)) 133 this->m_modeBasicARM = CS_MODE_ARM; 134 135 if (ImGui::RadioButton("hex.view.disassembler.arm.arm"_lang, this->m_modeBasicARM == CS_MODE_ARM)) 136 this->m_modeBasicARM = CS_MODE_ARM; 137 ImGui::SameLine(); 138 if (ImGui::RadioButton("hex.view.disassembler.arm.thumb"_lang, this->m_modeBasicARM == CS_MODE_THUMB)) 139 this->m_modeBasicARM = CS_MODE_THUMB; 140 141 if (ImGui::RadioButton("hex.view.disassembler.arm.default"_lang, (this->m_modeExtraARM & (CS_MODE_MCLASS | CS_MODE_V8)) == 0)) 142 this->m_modeExtraARM = cs_mode(0); 143 ImGui::SameLine(); 144 if (ImGui::RadioButton("hex.view.disassembler.arm.cortex_m"_lang, (this->m_modeExtraARM & (CS_MODE_MCLASS | CS_MODE_V8)) == CS_MODE_MCLASS)) 145 this->m_modeExtraARM = CS_MODE_MCLASS; 146 ImGui::SameLine(); 147 if (ImGui::RadioButton("hex.view.disassembler.arm.armv8"_lang, (this->m_modeExtraARM & (CS_MODE_MCLASS | CS_MODE_V8)) == CS_MODE_V8)) 148 this->m_modeExtraARM = CS_MODE_V8; 149 break; 150 case Architecture::MIPS: 151 this->m_modeBasicARM = cs_mode(0); 152 this->m_modeExtraARM = cs_mode(0); 153 this->m_modeBasicX86 = cs_mode(0); 154 this->m_modeBasicPPC = cs_mode(0); 155 this->m_sparcV9Mode = false; 156 157 if (this->m_modeBasicMIPS == cs_mode(0)) 158 this->m_modeBasicMIPS = CS_MODE_MIPS32; 159 160 if (ImGui::RadioButton("hex.view.disassembler.mips.mips32"_lang, this->m_modeBasicMIPS == CS_MODE_MIPS32)) 161 this->m_modeBasicMIPS = CS_MODE_MIPS32; 162 ImGui::SameLine(); 163 if (ImGui::RadioButton("hex.view.disassembler.mips.mips64"_lang, this->m_modeBasicMIPS == CS_MODE_MIPS64)) 164 this->m_modeBasicMIPS = CS_MODE_MIPS64; 165 ImGui::SameLine(); 166 if (ImGui::RadioButton("hex.view.disassembler.mips.mips32R6"_lang, this->m_modeBasicMIPS == CS_MODE_MIPS32R6)) 167 this->m_modeBasicMIPS = CS_MODE_MIPS32R6; 168 169 ImGui::Checkbox("hex.view.disassembler.mips.micro"_lang, &this->m_micoMode); 170 break; 171 case Architecture::X86: 172 this->m_modeBasicARM = cs_mode(0); 173 this->m_modeExtraARM = cs_mode(0); 174 this->m_modeBasicMIPS = cs_mode(0); 175 this->m_modeBasicPPC = cs_mode(0); 176 this->m_micoMode = false; 177 this->m_sparcV9Mode = false; 178 179 if (this->m_modeBasicX86 == cs_mode(0)) 180 this->m_modeBasicX86 = CS_MODE_16; 181 182 if (ImGui::RadioButton("hex.view.disassembler.x86.16bit"_lang, this->m_modeBasicX86 == CS_MODE_16)) 183 this->m_modeBasicX86 = CS_MODE_16; 184 ImGui::SameLine(); 185 if (ImGui::RadioButton("hex.view.disassembler.x86.32bit"_lang, this->m_modeBasicX86 == CS_MODE_32)) 186 this->m_modeBasicX86 = CS_MODE_32; 187 ImGui::SameLine(); 188 if (ImGui::RadioButton("hex.view.disassembler.x86.64bit"_lang, this->m_modeBasicX86 == CS_MODE_64)) 189 this->m_modeBasicX86 = CS_MODE_64; 190 break; 191 case Architecture::PPC: 192 this->m_modeBasicARM = cs_mode(0); 193 this->m_modeExtraARM = cs_mode(0); 194 this->m_modeBasicMIPS = cs_mode(0); 195 this->m_modeBasicX86 = cs_mode(0); 196 this->m_micoMode = false; 197 this->m_sparcV9Mode = false; 198 199 if (m_modeBasicPPC == cs_mode(0)) 200 this->m_modeBasicPPC = CS_MODE_32; 201 202 if (ImGui::RadioButton("hex.view.disassembler.ppc.32bit"_lang, this->m_modeBasicPPC == CS_MODE_32)) 203 this->m_modeBasicPPC = CS_MODE_32; 204 ImGui::SameLine(); 205 if (ImGui::RadioButton("hex.view.disassembler.ppc.64bit"_lang, this->m_modeBasicPPC == CS_MODE_64)) 206 this->m_modeBasicPPC = CS_MODE_64; 207 break; 208 case Architecture::SPARC: 209 this->m_modeBasicARM = cs_mode(0); 210 this->m_modeExtraARM = cs_mode(0); 211 this->m_modeBasicMIPS = cs_mode(0); 212 this->m_modeBasicX86 = cs_mode(0); 213 this->m_modeBasicPPC = cs_mode(0); 214 this->m_micoMode = false; 215 216 ImGui::Checkbox("hex.view.disassembler.sparc.v9"_lang, &this->m_sparcV9Mode); 217 break; 218 case Architecture::ARM64: 219 case Architecture::SYSZ: 220 case Architecture::XCORE: 221 case Architecture::M68K: 222 case Architecture::TMS320C64X: 223 case Architecture::M680X: 224 case Architecture::EVM: 225 this->m_modeBasicARM = cs_mode(0); 226 this->m_modeExtraARM = cs_mode(0); 227 this->m_modeBasicMIPS = cs_mode(0); 228 this->m_modeBasicX86 = cs_mode(0); 229 this->m_modeBasicPPC = cs_mode(0); 230 this->m_micoMode = false; 231 this->m_sparcV9Mode = false; 232 break; 233 } 234 235 } 236 ImGui::EndChild(); 237 238 ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x - 300) / 2); 239 if (ImGui::Button("hex.view.disassembler.disassemble"_lang, ImVec2(300, 20))) 240 this->m_shouldInvalidate = true; 241 ImGui::NewLine(); 242 243 ImGui::TextUnformatted("hex.view.disassembler.disassembly.title"_lang); 244 ImGui::Separator(); 245 246 if (ImGui::BeginTable("##disassembly", 4, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_Reorderable)) { 247 ImGui::TableSetupScrollFreeze(0, 1); 248 ImGui::TableSetupColumn("hex.view.disassembler.disassembly.address"_lang); 249 ImGui::TableSetupColumn("hex.view.disassembler.disassembly.offset"_lang); 250 ImGui::TableSetupColumn("hex.view.disassembler.disassembly.bytes"_lang); 251 ImGui::TableSetupColumn("hex.view.disassembler.disassembly.title"_lang); 252 253 ImGuiListClipper clipper; 254 clipper.Begin(this->m_disassembly.size()); 255 256 ImGui::TableHeadersRow(); 257 while (clipper.Step()) { 258 for (u64 i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { 259 ImGui::TableNextRow(); 260 ImGui::TableNextColumn(); 261 if (ImGui::Selectable(("##DisassemblyLine"s + std::to_string(i)).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) { 262 Region selectRegion = { this->m_disassembly[i].offset, this->m_disassembly[i].size }; 263 View::postEvent(Events::SelectionChangeRequest, selectRegion); 264 } 265 ImGui::SameLine(); 266 ImGui::Text("0x%llx", this->m_disassembly[i].address); 267 ImGui::TableNextColumn(); 268 ImGui::Text("0x%llx", this->m_disassembly[i].offset); 269 ImGui::TableNextColumn(); 270 ImGui::TextUnformatted(this->m_disassembly[i].bytes.c_str()); 271 ImGui::TableNextColumn(); 272 ImGui::TextColored(ImColor(0xFFD69C56), "%s", this->m_disassembly[i].mnemonic.c_str()); 273 ImGui::SameLine(); 274 ImGui::TextUnformatted(this->m_disassembly[i].operators.c_str()); 275 } 276 } 277 278 clipper.End(); 279 280 ImGui::EndTable(); 281 } 282 } 283 } 284 ImGui::End(); 285 } 286 drawMenu()287 void ViewDisassembler::drawMenu() { 288 289 } 290 291 }