1
0
mirror of synced 2025-01-11 05:42:15 +01:00

impr: Make disassembly view contain data per-provider

This commit is contained in:
WerWolv 2024-12-31 21:16:16 +01:00
parent c853349b78
commit 180f4926f8
2 changed files with 53 additions and 38 deletions

View File

@ -23,14 +23,14 @@ namespace hex::plugin::disasm {
private: private:
TaskHolder m_disassemblerTask; TaskHolder m_disassemblerTask;
u64 m_imageLoadAddress = 0; PerProvider<u64> m_imageLoadAddress;
u64 m_imageBaseAddress = 0; PerProvider<u64> m_imageBaseAddress;
ui::RegionType m_range = ui::RegionType::EntireData; PerProvider<ui::RegionType> m_range;
Region m_regionToDisassemble = { }; PerProvider<Region> m_regionToDisassemble;
std::unique_ptr<ContentRegistry::Disassembler::Architecture> m_currArchitecture = nullptr; PerProvider<std::unique_ptr<ContentRegistry::Disassembler::Architecture>> m_currArchitecture;
std::vector<ContentRegistry::Disassembler::Instruction> m_disassembly; PerProvider<std::vector<ContentRegistry::Disassembler::Instruction>> m_disassembly;
void disassemble(); void disassemble();
void exportToFile(); void exportToFile();

View File

@ -6,7 +6,6 @@
#include <fonts/vscode_icons.hpp> #include <fonts/vscode_icons.hpp>
#include <cstring>
#include <toasts/toast_notification.hpp> #include <toasts/toast_notification.hpp>
#include <wolv/literals.hpp> #include <wolv/literals.hpp>
@ -17,8 +16,8 @@ using namespace wolv::literals;
namespace hex::plugin::disasm { namespace hex::plugin::disasm {
ViewDisassembler::ViewDisassembler() : View::Window("hex.disassembler.view.disassembler.name", ICON_VS_FILE_CODE) { ViewDisassembler::ViewDisassembler() : View::Window("hex.disassembler.view.disassembler.name", ICON_VS_FILE_CODE) {
EventProviderDeleted::subscribe(this, [this](const auto*) { EventProviderDeleted::subscribe(this, [this](const auto *provider) {
m_disassembly.clear(); m_disassembly.get(provider).clear();
}); });
ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.menu.edit.disassemble_range" }, ICON_VS_DEBUG_LINE_BY_LINE, 3100, CTRLCMD + SHIFT + Keys::D, [this] { ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.menu.edit.disassemble_range" }, ICON_VS_DEBUG_LINE_BY_LINE, 3100, CTRLCMD + SHIFT + Keys::D, [this] {
@ -41,40 +40,45 @@ namespace hex::plugin::disasm {
} }
void ViewDisassembler::disassemble() { void ViewDisassembler::disassemble() {
m_disassembly.clear(); const auto provider = ImHexApi::Provider::get();
if (m_regionToDisassemble.getStartAddress() < m_imageBaseAddress) m_disassembly.get(provider).clear();
if (m_regionToDisassemble.get(provider).getStartAddress() < m_imageBaseAddress)
return; return;
m_disassemblerTask = TaskManager::createTask("hex.disassembler.view.disassembler.disassembling"_lang, m_regionToDisassemble.getSize(), [this](auto &task) { m_disassemblerTask = TaskManager::createTask("hex.disassembler.view.disassembler.disassembling"_lang, m_regionToDisassemble.get(provider).getSize(), [this, provider](auto &task) {
const auto &currArchitecture = m_currArchitecture.get(provider);
const auto region = m_regionToDisassemble.get(provider);
auto &disassembly = m_disassembly.get(provider);
// Create a capstone disassembler instance // Create a capstone disassembler instance
if (m_currArchitecture->start()) { if (currArchitecture->start()) {
auto provider = ImHexApi::Provider::get();
std::vector<u8> buffer(1_MiB, 0x00); std::vector<u8> buffer(1_MiB, 0x00);
const u64 codeOffset = m_regionToDisassemble.getStartAddress() - m_imageBaseAddress; const u64 codeOffset = region.getStartAddress() - m_imageBaseAddress;
// Read the data in chunks and disassemble it // Read the data in chunks and disassemble it
u64 instructionLoadAddress = m_imageLoadAddress + codeOffset; u64 instructionLoadAddress = m_imageLoadAddress + codeOffset;
u64 instructionDataAddress = m_regionToDisassemble.getStartAddress(); u64 instructionDataAddress = region.getStartAddress();
bool hadError = false; bool hadError = false;
while (instructionDataAddress < m_regionToDisassemble.getEndAddress()) { while (instructionDataAddress < region.getEndAddress()) {
// Read a chunk of data // Read a chunk of data
size_t bufferSize = std::min<u64>(buffer.size(), (m_regionToDisassemble.getEndAddress() - instructionDataAddress)); size_t bufferSize = std::min<u64>(buffer.size(), (region.getEndAddress() - instructionDataAddress));
provider->read(instructionDataAddress, buffer.data(), bufferSize); provider->read(instructionDataAddress, buffer.data(), bufferSize);
auto code = std::span(buffer.data(), bufferSize); auto code = std::span(buffer.data(), bufferSize);
// Ask capstone to disassemble the data // Ask capstone to disassemble the data
while (true) { while (true) {
auto instruction = m_currArchitecture->disassemble(m_imageBaseAddress, instructionLoadAddress, instructionDataAddress, code); auto instruction = currArchitecture->disassemble(m_imageBaseAddress, instructionLoadAddress, instructionDataAddress, code);
if (!instruction.has_value()) if (!instruction.has_value())
break; break;
task.update(instructionDataAddress); task.update(instructionDataAddress);
m_disassembly.push_back(instruction.value()); disassembly.push_back(instruction.value());
code = code.subspan(instruction->size); code = code.subspan(instruction->size);
instructionDataAddress += instruction->size; instructionDataAddress += instruction->size;
@ -89,15 +93,16 @@ namespace hex::plugin::disasm {
hadError = true; hadError = true;
} }
m_currArchitecture->end(); currArchitecture->end();
} }
}); });
} }
void ViewDisassembler::exportToFile() { void ViewDisassembler::exportToFile() {
TaskManager::createTask("hex.ui.common.processing"_lang, TaskManager::NoProgress, [this](auto &) { const auto provider = ImHexApi::Provider::get();
TaskManager::doLater([this] { TaskManager::createTask("hex.ui.common.processing"_lang, TaskManager::NoProgress, [this, provider](auto &) {
fs::openFileBrowser(fs::DialogMode::Save, {}, [this](const std::fs::path &path) { TaskManager::doLater([this, provider] {
fs::openFileBrowser(fs::DialogMode::Save, {}, [this, provider](const std::fs::path &path) {
auto p = path; auto p = path;
if (p.extension() != ".asm") if (p.extension() != ".asm")
p.replace_filename(hex::format("{}{}", p.filename().string(), ".asm")); p.replace_filename(hex::format("{}{}", p.filename().string(), ".asm"));
@ -109,7 +114,7 @@ namespace hex::plugin::disasm {
} }
// As disassembly code can be quite long, we prefer writing each disassembled instruction to file // As disassembly code can be quite long, we prefer writing each disassembled instruction to file
for (const ContentRegistry::Disassembler::Instruction& instruction : m_disassembly) { for (const ContentRegistry::Disassembler::Instruction& instruction : m_disassembly.get(provider)) {
// We test for a "bugged" case that should never happen - the instruction should always have a mnemonic // We test for a "bugged" case that should never happen - the instruction should always have a mnemonic
if (instruction.mnemonic.empty()) if (instruction.mnemonic.empty())
continue; continue;
@ -127,20 +132,27 @@ namespace hex::plugin::disasm {
void ViewDisassembler::drawContent() { void ViewDisassembler::drawContent() {
auto provider = ImHexApi::Provider::get(); auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid() && provider->isReadable()) { if (ImHexApi::Provider::isValid() && provider->isReadable()) {
auto &region = m_regionToDisassemble.get(provider);
auto &range = m_range.get(provider);
// Draw region selection picker // Draw region selection picker
ui::regionSelectionPicker(&m_regionToDisassemble, provider, &m_range, true, true); ui::regionSelectionPicker(&region, provider, &range, true, true);
ImGuiExt::Header("hex.disassembler.view.disassembler.position"_lang); ImGuiExt::Header("hex.disassembler.view.disassembler.position"_lang);
// Draw base address input // Draw base address input
ImGuiExt::InputHexadecimal("hex.disassembler.view.disassembler.image_load_address"_lang, &m_imageLoadAddress, ImGuiInputTextFlags_CharsHexadecimal); {
auto &address = m_imageLoadAddress.get(provider);
ImGuiExt::InputHexadecimal("hex.disassembler.view.disassembler.image_load_address"_lang, &address, ImGuiInputTextFlags_CharsHexadecimal);
ImGui::SameLine(); ImGui::SameLine();
ImGuiExt::HelpHover("hex.disassembler.view.disassembler.image_load_address.hint"_lang, ICON_VS_INFO); ImGuiExt::HelpHover("hex.disassembler.view.disassembler.image_load_address.hint"_lang, ICON_VS_INFO);
}
// Draw code region start address input // Draw code region start address input
ImGui::BeginDisabled(m_range == ui::RegionType::EntireData); ImGui::BeginDisabled(m_range == ui::RegionType::EntireData);
{ {
ImGuiExt::InputHexadecimal("hex.disassembler.view.disassembler.image_base_address"_lang, &m_imageBaseAddress, ImGuiInputTextFlags_CharsHexadecimal); auto &address = m_imageBaseAddress.get(provider);
ImGuiExt::InputHexadecimal("hex.disassembler.view.disassembler.image_base_address"_lang, &address, ImGuiInputTextFlags_CharsHexadecimal);
ImGui::SameLine(); ImGui::SameLine();
ImGuiExt::HelpHover("hex.disassembler.view.disassembler.image_base_address.hint"_lang, ICON_VS_INFO); ImGuiExt::HelpHover("hex.disassembler.view.disassembler.image_base_address.hint"_lang, ICON_VS_INFO);
} }
@ -155,13 +167,14 @@ namespace hex::plugin::disasm {
if (architectures.empty()) { if (architectures.empty()) {
ImGuiExt::TextSpinner("hex.disassembler.view.disassembler.arch"_lang); ImGuiExt::TextSpinner("hex.disassembler.view.disassembler.arch"_lang);
} else { } else {
if (m_currArchitecture == nullptr) { const auto &currArchitecture = m_currArchitecture.get(provider);
if (currArchitecture == nullptr) {
m_currArchitecture = architectures.begin()->second(); m_currArchitecture = architectures.begin()->second();
} }
if (ImGui::BeginCombo("hex.disassembler.view.disassembler.arch"_lang, m_currArchitecture->getName().c_str())) { if (ImGui::BeginCombo("hex.disassembler.view.disassembler.arch"_lang, currArchitecture->getName().c_str())) {
for (const auto &[name, creator] : architectures) { for (const auto &[name, creator] : architectures) {
if (ImGui::Selectable(name.c_str(), name == m_currArchitecture->getName())) { if (ImGui::Selectable(name.c_str(), name == currArchitecture->getName())) {
m_currArchitecture = creator(); m_currArchitecture = creator();
} }
} }
@ -170,23 +183,25 @@ namespace hex::plugin::disasm {
// Draw sub-settings for each architecture // Draw sub-settings for each architecture
if (ImGuiExt::BeginBox()) { if (ImGuiExt::BeginBox()) {
m_currArchitecture->drawSettings(); currArchitecture->drawSettings();
} }
ImGuiExt::EndBox(); ImGuiExt::EndBox();
} }
} }
// Draw disassemble button // Draw disassemble button
ImGui::BeginDisabled(m_disassemblerTask.isRunning() || m_regionToDisassemble.getStartAddress() < m_imageBaseAddress); ImGui::BeginDisabled(m_disassemblerTask.isRunning() || region.getStartAddress() < m_imageBaseAddress);
{ {
if (ImGuiExt::DimmedButton("hex.disassembler.view.disassembler.disassemble"_lang)) if (ImGuiExt::DimmedButton("hex.disassembler.view.disassembler.disassemble"_lang))
this->disassemble(); this->disassemble();
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
const auto &disassembly = m_disassembly.get(provider);
// Draw export to file icon button // Draw export to file icon button
ImGui::SameLine(); ImGui::SameLine();
ImGui::BeginDisabled(m_disassemblerTask.isRunning() || m_disassembly.empty()); ImGui::BeginDisabled(m_disassemblerTask.isRunning() || disassembly.empty());
{ {
if (ImGuiExt::DimmedIconButton(ICON_VS_EXPORT, ImGui::GetStyleColorVec4(ImGuiCol_Text))) if (ImGuiExt::DimmedIconButton(ICON_VS_EXPORT, ImGui::GetStyleColorVec4(ImGuiCol_Text)))
this->exportToFile(); this->exportToFile();
@ -214,12 +229,12 @@ namespace hex::plugin::disasm {
if (!m_disassemblerTask.isRunning()) { if (!m_disassemblerTask.isRunning()) {
ImGuiListClipper clipper; ImGuiListClipper clipper;
clipper.Begin(m_disassembly.size()); clipper.Begin(disassembly.size());
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
while (clipper.Step()) { while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
const auto &instruction = m_disassembly[i]; const auto &instruction = disassembly[i];
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();