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 }