2021-12-07 22:47:41 +01:00
|
|
|
#include "content/views/view_disassembler.hpp"
|
2024-12-09 21:35:08 +01:00
|
|
|
#include "hex/api/content_registry.hpp"
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2021-01-13 17:28:27 +01:00
|
|
|
#include <hex/providers/provider.hpp>
|
2021-08-29 22:15:18 +02:00
|
|
|
#include <hex/helpers/fmt.hpp>
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2024-12-14 20:36:09 +01:00
|
|
|
#include <fonts/vscode_icons.hpp>
|
2024-01-28 22:14:59 +01:00
|
|
|
|
2020-11-22 23:07:50 +01:00
|
|
|
#include <cstring>
|
feat: Added export disassembler results to ASM file (#1987)
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
This PR implements the feature request #1781, that suggests adding a
button to export disassembled instructions into an ASM file.
### Implementation description
This adds a button to export the current disassembled instructions to an
ASM file. Said file is suffixed by an `.asm` extension if not specified
at file creation.
*Note: the file is written to for every `Disassembly` item in the
vector, as it was the easiest and most memory-conservative way of doing
it.*
The file creation task is implemented based on IPS patch exports, so it
fits the same pattern.
A `ToastError` is raised when the ASM export could not complete
successfully.
Translations have been implemented for both `en_US` and `de_DE` for the
two new keys:
- `hex.disassembler.view.disassembler.export`: file export button
- `hex.disassembler.view.disassembler.export.popup.error`: error popup
text
### Screenshots
The button is disabled when the disassembler is working, or when the
disassembly vector is empty.
Here is a complete breakdown of the visual changes:
![image](https://github.com/user-attachments/assets/af0ce701-9d77-45f1-9a5a-90d68d00bb0d)
### Additional things
As expected, the exporter writes every item's `mnemonic` and `operators`
to the file, producing an output like this:
`example.asm`
```asm
.byte 0x7f, 0x45, 0x4c, 0x46
andeq r0, r1, r2, lsl #2
andeq r0, r0, r0
andeq r0, r0, r0
eorseq r0, lr, r3
andeq r0, r0, r1
andeq r1, r0, r0, asr #32
andeq r0, r0, r0
andeq r0, r0, r0, asr #32
```
---------
Signed-off-by: BioTheWolff <47079795+BioTheWolff@users.noreply.github.com>
2024-12-05 23:04:38 +01:00
|
|
|
#include <toasts/toast_notification.hpp>
|
2021-02-22 11:56:33 +01:00
|
|
|
|
2024-12-10 20:33:28 +01:00
|
|
|
#include <wolv/literals.hpp>
|
|
|
|
|
2020-11-22 23:07:50 +01:00
|
|
|
using namespace std::literals::string_literals;
|
2024-12-10 20:33:28 +01:00
|
|
|
using namespace wolv::literals;
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2023-12-23 21:09:41 +01:00
|
|
|
namespace hex::plugin::disasm {
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2024-01-08 21:51:48 +01:00
|
|
|
ViewDisassembler::ViewDisassembler() : View::Window("hex.disassembler.view.disassembler.name", ICON_VS_FILE_CODE) {
|
2023-12-08 10:29:44 +01:00
|
|
|
EventProviderDeleted::subscribe(this, [this](const auto*) {
|
2023-12-19 13:10:25 +01:00
|
|
|
m_disassembly.clear();
|
2021-12-05 22:09:43 +01:00
|
|
|
});
|
2024-12-09 21:35:08 +01:00
|
|
|
|
|
|
|
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] {
|
|
|
|
ImGui::SetWindowFocus(this->getName().c_str());
|
|
|
|
this->getWindowOpenState() = true;
|
|
|
|
|
|
|
|
m_range = ui::RegionType::Region;
|
2024-12-10 20:33:28 +01:00
|
|
|
m_regionToDisassemble = ImHexApi::HexEditor::getSelection()->getRegion();
|
2024-12-09 21:35:08 +01:00
|
|
|
|
|
|
|
this->disassemble();
|
|
|
|
}, [this]{
|
|
|
|
return ImHexApi::HexEditor::isSelectionValid() && !this->m_disassemblerTask.isRunning();
|
|
|
|
});
|
2020-11-22 23:07:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ViewDisassembler::~ViewDisassembler() {
|
2023-12-08 10:29:44 +01:00
|
|
|
EventDataChanged::unsubscribe(this);
|
|
|
|
EventRegionSelected::unsubscribe(this);
|
|
|
|
EventProviderDeleted::unsubscribe(this);
|
2020-11-22 23:07:50 +01:00
|
|
|
}
|
|
|
|
|
2021-02-22 11:56:33 +01:00
|
|
|
void ViewDisassembler::disassemble() {
|
2023-12-19 13:10:25 +01:00
|
|
|
m_disassembly.clear();
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2024-12-10 20:33:28 +01:00
|
|
|
if (m_regionToDisassemble.getStartAddress() < m_imageBaseAddress)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_disassemblerTask = TaskManager::createTask("hex.disassembler.view.disassembler.disassembling"_lang, m_regionToDisassemble.getSize(), [this](auto &task) {
|
2023-08-29 12:14:12 +02:00
|
|
|
// Create a capstone disassembler instance
|
2024-12-26 18:41:34 +01:00
|
|
|
if (m_currArchitecture->start()) {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2024-12-10 20:33:28 +01:00
|
|
|
std::vector<u8> buffer(1_MiB, 0x00);
|
|
|
|
|
|
|
|
const u64 codeOffset = m_regionToDisassemble.getStartAddress() - m_imageBaseAddress;
|
2021-12-16 23:48:52 +01:00
|
|
|
|
2023-08-29 12:14:12 +02:00
|
|
|
// Read the data in chunks and disassemble it
|
2024-12-10 20:33:28 +01:00
|
|
|
u64 instructionLoadAddress = m_imageLoadAddress + codeOffset;
|
|
|
|
u64 instructionDataAddress = m_regionToDisassemble.getStartAddress();
|
2021-12-16 23:48:52 +01:00
|
|
|
|
2024-12-10 20:33:28 +01:00
|
|
|
bool hadError = false;
|
|
|
|
while (instructionDataAddress < m_regionToDisassemble.getEndAddress()) {
|
2023-08-29 12:14:12 +02:00
|
|
|
// Read a chunk of data
|
2024-12-10 20:33:28 +01:00
|
|
|
size_t bufferSize = std::min<u64>(buffer.size(), (m_regionToDisassemble.getEndAddress() - instructionDataAddress));
|
|
|
|
provider->read(instructionDataAddress, buffer.data(), bufferSize);
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2024-12-26 18:41:34 +01:00
|
|
|
auto code = std::span(buffer.data(), bufferSize);
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2024-12-26 18:41:34 +01:00
|
|
|
// Ask capstone to disassemble the data
|
|
|
|
while (true) {
|
|
|
|
auto instruction = m_currArchitecture->disassemble(m_imageBaseAddress, instructionLoadAddress, instructionDataAddress, code);
|
|
|
|
if (!instruction.has_value())
|
|
|
|
break;
|
2024-12-10 20:33:28 +01:00
|
|
|
|
2024-12-26 18:41:34 +01:00
|
|
|
task.update(instructionDataAddress);
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2024-12-26 18:41:34 +01:00
|
|
|
m_disassembly.push_back(instruction.value());
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2024-12-26 18:41:34 +01:00
|
|
|
code = code.subspan(instruction->size);
|
2024-12-25 16:36:53 +01:00
|
|
|
instructionDataAddress += instruction->size;
|
2024-12-26 18:41:34 +01:00
|
|
|
instructionLoadAddress += instruction->size;
|
2024-12-10 20:33:28 +01:00
|
|
|
hadError = false;
|
2024-12-26 18:41:34 +01:00
|
|
|
|
|
|
|
if (code.empty())
|
|
|
|
break;
|
2020-11-22 23:07:50 +01:00
|
|
|
}
|
|
|
|
|
2024-12-10 20:33:28 +01:00
|
|
|
if (hadError) break;
|
|
|
|
hadError = true;
|
2020-11-22 23:07:50 +01:00
|
|
|
}
|
|
|
|
|
2024-12-26 18:41:34 +01:00
|
|
|
m_currArchitecture->end();
|
2020-11-22 23:07:50 +01:00
|
|
|
}
|
2022-08-17 16:15:36 +02:00
|
|
|
});
|
2021-02-22 11:56:33 +01:00
|
|
|
}
|
|
|
|
|
feat: Added export disassembler results to ASM file (#1987)
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
This PR implements the feature request #1781, that suggests adding a
button to export disassembled instructions into an ASM file.
### Implementation description
This adds a button to export the current disassembled instructions to an
ASM file. Said file is suffixed by an `.asm` extension if not specified
at file creation.
*Note: the file is written to for every `Disassembly` item in the
vector, as it was the easiest and most memory-conservative way of doing
it.*
The file creation task is implemented based on IPS patch exports, so it
fits the same pattern.
A `ToastError` is raised when the ASM export could not complete
successfully.
Translations have been implemented for both `en_US` and `de_DE` for the
two new keys:
- `hex.disassembler.view.disassembler.export`: file export button
- `hex.disassembler.view.disassembler.export.popup.error`: error popup
text
### Screenshots
The button is disabled when the disassembler is working, or when the
disassembly vector is empty.
Here is a complete breakdown of the visual changes:
![image](https://github.com/user-attachments/assets/af0ce701-9d77-45f1-9a5a-90d68d00bb0d)
### Additional things
As expected, the exporter writes every item's `mnemonic` and `operators`
to the file, producing an output like this:
`example.asm`
```asm
.byte 0x7f, 0x45, 0x4c, 0x46
andeq r0, r1, r2, lsl #2
andeq r0, r0, r0
andeq r0, r0, r0
eorseq r0, lr, r3
andeq r0, r0, r1
andeq r1, r0, r0, asr #32
andeq r0, r0, r0
andeq r0, r0, r0, asr #32
```
---------
Signed-off-by: BioTheWolff <47079795+BioTheWolff@users.noreply.github.com>
2024-12-05 23:04:38 +01:00
|
|
|
void ViewDisassembler::exportToFile() {
|
|
|
|
TaskManager::createTask("hex.ui.common.processing"_lang, TaskManager::NoProgress, [this](auto &) {
|
|
|
|
TaskManager::doLater([this] {
|
|
|
|
fs::openFileBrowser(fs::DialogMode::Save, {}, [this](const std::fs::path &path) {
|
|
|
|
auto p = path;
|
|
|
|
if (p.extension() != ".asm")
|
|
|
|
p.replace_filename(hex::format("{}{}", p.filename().string(), ".asm"));
|
|
|
|
auto file = wolv::io::File(p, wolv::io::File::Mode::Create);
|
|
|
|
|
|
|
|
if (!file.isValid()) {
|
|
|
|
ui::ToastError::open("hex.disassembler.view.disassembler.export.popup.error"_lang);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// As disassembly code can be quite long, we prefer writing each disassembled instruction to file
|
2024-12-26 18:41:34 +01:00
|
|
|
for (const ContentRegistry::Disassembler::Instruction& instruction : m_disassembly) {
|
feat: Added export disassembler results to ASM file (#1987)
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
This PR implements the feature request #1781, that suggests adding a
button to export disassembled instructions into an ASM file.
### Implementation description
This adds a button to export the current disassembled instructions to an
ASM file. Said file is suffixed by an `.asm` extension if not specified
at file creation.
*Note: the file is written to for every `Disassembly` item in the
vector, as it was the easiest and most memory-conservative way of doing
it.*
The file creation task is implemented based on IPS patch exports, so it
fits the same pattern.
A `ToastError` is raised when the ASM export could not complete
successfully.
Translations have been implemented for both `en_US` and `de_DE` for the
two new keys:
- `hex.disassembler.view.disassembler.export`: file export button
- `hex.disassembler.view.disassembler.export.popup.error`: error popup
text
### Screenshots
The button is disabled when the disassembler is working, or when the
disassembly vector is empty.
Here is a complete breakdown of the visual changes:
![image](https://github.com/user-attachments/assets/af0ce701-9d77-45f1-9a5a-90d68d00bb0d)
### Additional things
As expected, the exporter writes every item's `mnemonic` and `operators`
to the file, producing an output like this:
`example.asm`
```asm
.byte 0x7f, 0x45, 0x4c, 0x46
andeq r0, r1, r2, lsl #2
andeq r0, r0, r0
andeq r0, r0, r0
eorseq r0, lr, r3
andeq r0, r0, r1
andeq r1, r0, r0, asr #32
andeq r0, r0, r0
andeq r0, r0, r0, asr #32
```
---------
Signed-off-by: BioTheWolff <47079795+BioTheWolff@users.noreply.github.com>
2024-12-05 23:04:38 +01:00
|
|
|
// We test for a "bugged" case that should never happen - the instruction should always have a mnemonic
|
2024-12-26 18:41:34 +01:00
|
|
|
if (instruction.mnemonic.empty())
|
feat: Added export disassembler results to ASM file (#1987)
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
This PR implements the feature request #1781, that suggests adding a
button to export disassembled instructions into an ASM file.
### Implementation description
This adds a button to export the current disassembled instructions to an
ASM file. Said file is suffixed by an `.asm` extension if not specified
at file creation.
*Note: the file is written to for every `Disassembly` item in the
vector, as it was the easiest and most memory-conservative way of doing
it.*
The file creation task is implemented based on IPS patch exports, so it
fits the same pattern.
A `ToastError` is raised when the ASM export could not complete
successfully.
Translations have been implemented for both `en_US` and `de_DE` for the
two new keys:
- `hex.disassembler.view.disassembler.export`: file export button
- `hex.disassembler.view.disassembler.export.popup.error`: error popup
text
### Screenshots
The button is disabled when the disassembler is working, or when the
disassembly vector is empty.
Here is a complete breakdown of the visual changes:
![image](https://github.com/user-attachments/assets/af0ce701-9d77-45f1-9a5a-90d68d00bb0d)
### Additional things
As expected, the exporter writes every item's `mnemonic` and `operators`
to the file, producing an output like this:
`example.asm`
```asm
.byte 0x7f, 0x45, 0x4c, 0x46
andeq r0, r1, r2, lsl #2
andeq r0, r0, r0
andeq r0, r0, r0
eorseq r0, lr, r3
andeq r0, r0, r1
andeq r1, r0, r0, asr #32
andeq r0, r0, r0
andeq r0, r0, r0, asr #32
```
---------
Signed-off-by: BioTheWolff <47079795+BioTheWolff@users.noreply.github.com>
2024-12-05 23:04:38 +01:00
|
|
|
continue;
|
|
|
|
|
2024-12-26 18:41:34 +01:00
|
|
|
if (instruction.operators.empty())
|
|
|
|
file.writeString(hex::format("{}\n", instruction.mnemonic));
|
feat: Added export disassembler results to ASM file (#1987)
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
This PR implements the feature request #1781, that suggests adding a
button to export disassembled instructions into an ASM file.
### Implementation description
This adds a button to export the current disassembled instructions to an
ASM file. Said file is suffixed by an `.asm` extension if not specified
at file creation.
*Note: the file is written to for every `Disassembly` item in the
vector, as it was the easiest and most memory-conservative way of doing
it.*
The file creation task is implemented based on IPS patch exports, so it
fits the same pattern.
A `ToastError` is raised when the ASM export could not complete
successfully.
Translations have been implemented for both `en_US` and `de_DE` for the
two new keys:
- `hex.disassembler.view.disassembler.export`: file export button
- `hex.disassembler.view.disassembler.export.popup.error`: error popup
text
### Screenshots
The button is disabled when the disassembler is working, or when the
disassembly vector is empty.
Here is a complete breakdown of the visual changes:
![image](https://github.com/user-attachments/assets/af0ce701-9d77-45f1-9a5a-90d68d00bb0d)
### Additional things
As expected, the exporter writes every item's `mnemonic` and `operators`
to the file, producing an output like this:
`example.asm`
```asm
.byte 0x7f, 0x45, 0x4c, 0x46
andeq r0, r1, r2, lsl #2
andeq r0, r0, r0
andeq r0, r0, r0
eorseq r0, lr, r3
andeq r0, r0, r1
andeq r1, r0, r0, asr #32
andeq r0, r0, r0
andeq r0, r0, r0, asr #32
```
---------
Signed-off-by: BioTheWolff <47079795+BioTheWolff@users.noreply.github.com>
2024-12-05 23:04:38 +01:00
|
|
|
else
|
2024-12-26 18:41:34 +01:00
|
|
|
file.writeString(hex::format("{} {}\n", instruction.mnemonic, instruction.operators));
|
feat: Added export disassembler results to ASM file (#1987)
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
This PR implements the feature request #1781, that suggests adding a
button to export disassembled instructions into an ASM file.
### Implementation description
This adds a button to export the current disassembled instructions to an
ASM file. Said file is suffixed by an `.asm` extension if not specified
at file creation.
*Note: the file is written to for every `Disassembly` item in the
vector, as it was the easiest and most memory-conservative way of doing
it.*
The file creation task is implemented based on IPS patch exports, so it
fits the same pattern.
A `ToastError` is raised when the ASM export could not complete
successfully.
Translations have been implemented for both `en_US` and `de_DE` for the
two new keys:
- `hex.disassembler.view.disassembler.export`: file export button
- `hex.disassembler.view.disassembler.export.popup.error`: error popup
text
### Screenshots
The button is disabled when the disassembler is working, or when the
disassembly vector is empty.
Here is a complete breakdown of the visual changes:
![image](https://github.com/user-attachments/assets/af0ce701-9d77-45f1-9a5a-90d68d00bb0d)
### Additional things
As expected, the exporter writes every item's `mnemonic` and `operators`
to the file, producing an output like this:
`example.asm`
```asm
.byte 0x7f, 0x45, 0x4c, 0x46
andeq r0, r1, r2, lsl #2
andeq r0, r0, r0
andeq r0, r0, r0
eorseq r0, lr, r3
andeq r0, r0, r1
andeq r1, r0, r0, asr #32
andeq r0, r0, r0
andeq r0, r0, r0, asr #32
```
---------
Signed-off-by: BioTheWolff <47079795+BioTheWolff@users.noreply.github.com>
2024-12-05 23:04:38 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-02-22 11:56:33 +01:00
|
|
|
void ViewDisassembler::drawContent() {
|
2023-11-21 13:47:50 +01:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
|
2024-12-10 20:33:28 +01:00
|
|
|
// Draw region selection picker
|
2024-12-15 10:52:11 +01:00
|
|
|
ui::regionSelectionPicker(&m_regionToDisassemble, provider, &m_range, true, true);
|
|
|
|
|
|
|
|
ImGuiExt::Header("hex.disassembler.view.disassembler.position"_lang);
|
2024-12-10 20:33:28 +01:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw base address input
|
2024-12-10 20:33:28 +01:00
|
|
|
ImGuiExt::InputHexadecimal("hex.disassembler.view.disassembler.image_load_address"_lang, &m_imageLoadAddress, ImGuiInputTextFlags_CharsHexadecimal);
|
2024-12-24 10:57:09 +01:00
|
|
|
ImGui::SameLine();
|
|
|
|
ImGuiExt::HelpHover("hex.disassembler.view.disassembler.image_load_address.hint"_lang, ICON_VS_INFO);
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2024-12-10 20:33:28 +01:00
|
|
|
// Draw code region start address input
|
|
|
|
ImGui::BeginDisabled(m_range == ui::RegionType::EntireData);
|
|
|
|
{
|
|
|
|
ImGuiExt::InputHexadecimal("hex.disassembler.view.disassembler.image_base_address"_lang, &m_imageBaseAddress, ImGuiInputTextFlags_CharsHexadecimal);
|
2024-12-24 10:57:09 +01:00
|
|
|
ImGui::SameLine();
|
|
|
|
ImGuiExt::HelpHover("hex.disassembler.view.disassembler.image_base_address.hint"_lang, ICON_VS_INFO);
|
2024-12-10 20:33:28 +01:00
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw settings
|
|
|
|
{
|
2023-12-23 21:09:41 +01:00
|
|
|
ImGuiExt::Header("hex.ui.common.settings"_lang);
|
2022-08-07 12:20:40 +02:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw architecture selector
|
2024-12-26 18:41:34 +01:00
|
|
|
const auto &architectures = ContentRegistry::Disassembler::impl::getArchitectures();
|
|
|
|
if (architectures.empty()) {
|
|
|
|
ImGuiExt::TextSpinner("hex.disassembler.view.disassembler.arch"_lang);
|
|
|
|
} else {
|
|
|
|
if (m_currArchitecture == nullptr) {
|
|
|
|
m_currArchitecture = architectures.begin()->second();
|
|
|
|
}
|
2023-11-21 13:47:50 +01:00
|
|
|
|
2024-12-26 18:41:34 +01:00
|
|
|
if (ImGui::BeginCombo("hex.disassembler.view.disassembler.arch"_lang, m_currArchitecture->getName().c_str())) {
|
|
|
|
for (const auto &[name, creator] : architectures) {
|
|
|
|
if (ImGui::Selectable(name.c_str(), name == m_currArchitecture->getName())) {
|
|
|
|
m_currArchitecture = creator();
|
2023-11-21 13:47:50 +01:00
|
|
|
}
|
2024-12-26 18:41:34 +01:00
|
|
|
}
|
|
|
|
ImGui::EndCombo();
|
2020-11-22 23:07:50 +01:00
|
|
|
}
|
|
|
|
|
2024-12-26 18:41:34 +01:00
|
|
|
// Draw sub-settings for each architecture
|
|
|
|
if (ImGuiExt::BeginBox()) {
|
|
|
|
m_currArchitecture->drawSettings();
|
2024-06-16 15:06:30 +02:00
|
|
|
}
|
2024-12-26 18:41:34 +01:00
|
|
|
ImGuiExt::EndBox();
|
2022-05-27 20:42:07 +02:00
|
|
|
}
|
2023-11-21 13:47:50 +01:00
|
|
|
}
|
2021-02-22 11:56:33 +01:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw disassemble button
|
2024-12-10 20:33:28 +01:00
|
|
|
ImGui::BeginDisabled(m_disassemblerTask.isRunning() || m_regionToDisassemble.getStartAddress() < m_imageBaseAddress);
|
2023-11-21 13:47:50 +01:00
|
|
|
{
|
2024-12-24 10:57:09 +01:00
|
|
|
if (ImGuiExt::DimmedButton("hex.disassembler.view.disassembler.disassemble"_lang))
|
2023-11-21 13:47:50 +01:00
|
|
|
this->disassemble();
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
|
feat: Added export disassembler results to ASM file (#1987)
### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
This PR implements the feature request #1781, that suggests adding a
button to export disassembled instructions into an ASM file.
### Implementation description
This adds a button to export the current disassembled instructions to an
ASM file. Said file is suffixed by an `.asm` extension if not specified
at file creation.
*Note: the file is written to for every `Disassembly` item in the
vector, as it was the easiest and most memory-conservative way of doing
it.*
The file creation task is implemented based on IPS patch exports, so it
fits the same pattern.
A `ToastError` is raised when the ASM export could not complete
successfully.
Translations have been implemented for both `en_US` and `de_DE` for the
two new keys:
- `hex.disassembler.view.disassembler.export`: file export button
- `hex.disassembler.view.disassembler.export.popup.error`: error popup
text
### Screenshots
The button is disabled when the disassembler is working, or when the
disassembly vector is empty.
Here is a complete breakdown of the visual changes:
![image](https://github.com/user-attachments/assets/af0ce701-9d77-45f1-9a5a-90d68d00bb0d)
### Additional things
As expected, the exporter writes every item's `mnemonic` and `operators`
to the file, producing an output like this:
`example.asm`
```asm
.byte 0x7f, 0x45, 0x4c, 0x46
andeq r0, r1, r2, lsl #2
andeq r0, r0, r0
andeq r0, r0, r0
eorseq r0, lr, r3
andeq r0, r0, r1
andeq r1, r0, r0, asr #32
andeq r0, r0, r0
andeq r0, r0, r0, asr #32
```
---------
Signed-off-by: BioTheWolff <47079795+BioTheWolff@users.noreply.github.com>
2024-12-05 23:04:38 +01:00
|
|
|
// Draw export to file icon button
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginDisabled(m_disassemblerTask.isRunning() || m_disassembly.empty());
|
|
|
|
{
|
|
|
|
if (ImGuiExt::DimmedIconButton(ICON_VS_EXPORT, ImGui::GetStyleColorVec4(ImGuiCol_Text)))
|
|
|
|
this->exportToFile();
|
|
|
|
}
|
|
|
|
ImGui::EndDisabled();
|
|
|
|
ImGuiExt::InfoTooltip("hex.disassembler.view.disassembler.export"_lang);
|
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw a spinner if the disassembler is running
|
2023-12-19 13:10:25 +01:00
|
|
|
if (m_disassemblerTask.isRunning()) {
|
2023-12-23 21:09:41 +01:00
|
|
|
ImGuiExt::TextSpinner("hex.disassembler.view.disassembler.disassembling"_lang);
|
2023-11-21 13:47:50 +01:00
|
|
|
}
|
2021-02-22 11:56:33 +01:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
ImGui::NewLine();
|
2020-11-28 16:15:12 +01:00
|
|
|
|
2023-12-23 21:09:41 +01:00
|
|
|
ImGui::TextUnformatted("hex.disassembler.view.disassembler.disassembly.title"_lang);
|
2023-11-21 13:47:50 +01:00
|
|
|
ImGui::Separator();
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw disassembly table
|
|
|
|
if (ImGui::BeginTable("##disassembly", 4, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) {
|
|
|
|
ImGui::TableSetupScrollFreeze(0, 1);
|
2023-12-23 21:09:41 +01:00
|
|
|
ImGui::TableSetupColumn("hex.disassembler.view.disassembler.disassembly.address"_lang);
|
|
|
|
ImGui::TableSetupColumn("hex.disassembler.view.disassembler.disassembly.offset"_lang);
|
|
|
|
ImGui::TableSetupColumn("hex.disassembler.view.disassembler.disassembly.bytes"_lang);
|
|
|
|
ImGui::TableSetupColumn("hex.disassembler.view.disassembler.disassembly.title"_lang);
|
2020-11-23 15:22:26 +01:00
|
|
|
|
2023-12-19 13:10:25 +01:00
|
|
|
if (!m_disassemblerTask.isRunning()) {
|
2023-11-21 13:47:50 +01:00
|
|
|
ImGuiListClipper clipper;
|
2023-12-19 13:10:25 +01:00
|
|
|
clipper.Begin(m_disassembly.size());
|
2022-01-10 21:38:52 +01:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
ImGui::TableHeadersRow();
|
|
|
|
while (clipper.Step()) {
|
|
|
|
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
|
2023-12-19 13:10:25 +01:00
|
|
|
const auto &instruction = m_disassembly[i];
|
2023-08-29 12:14:12 +02:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableNextColumn();
|
2023-08-29 12:14:12 +02:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw a selectable label for the address
|
|
|
|
ImGui::PushID(i);
|
|
|
|
if (ImGui::Selectable("##DisassemblyLine", false, ImGuiSelectableFlags_SpanAllColumns)) {
|
|
|
|
ImHexApi::HexEditor::setSelection(instruction.offset, instruction.size);
|
|
|
|
}
|
|
|
|
ImGui::PopID();
|
2023-08-29 12:14:12 +02:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw instruction address
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGuiExt::TextFormatted("0x{0:X}", instruction.address);
|
2023-08-29 12:14:12 +02:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw instruction offset
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGuiExt::TextFormatted("0x{0:X}", instruction.offset);
|
2023-08-29 12:14:12 +02:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw instruction bytes
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::TextUnformatted(instruction.bytes.c_str());
|
2023-08-29 12:14:12 +02:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
// Draw instruction mnemonic and operands
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGuiExt::TextFormattedColored(ImColor(0xFFD69C56), "{}", instruction.mnemonic);
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::TextUnformatted(instruction.operators.c_str());
|
2020-11-22 23:07:50 +01:00
|
|
|
}
|
2022-01-10 21:38:52 +01:00
|
|
|
}
|
2020-11-22 23:07:50 +01:00
|
|
|
|
2023-11-21 13:47:50 +01:00
|
|
|
clipper.End();
|
2020-11-22 23:07:50 +01:00
|
|
|
}
|
2023-11-21 13:47:50 +01:00
|
|
|
|
|
|
|
ImGui::EndTable();
|
2020-11-22 23:07:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-20 11:37:45 +00:00
|
|
|
}
|