feat: Initial implementation of improved disassembler
This commit is contained in:
parent
f71fa2f704
commit
2a55cd8a4f
@ -22,13 +22,13 @@ using ImGuiInputTextFlags = int;
|
|||||||
struct ImColor;
|
struct ImColor;
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
class View;
|
class View;
|
||||||
class Shortcut;
|
class Shortcut;
|
||||||
|
|
||||||
namespace dp {
|
namespace dp {
|
||||||
class Node;
|
class Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace prv {
|
namespace prv {
|
||||||
class Provider;
|
class Provider;
|
||||||
}
|
}
|
||||||
@ -43,12 +43,9 @@ namespace hex {
|
|||||||
plugins when needed.
|
plugins when needed.
|
||||||
*/
|
*/
|
||||||
namespace ContentRegistry {
|
namespace ContentRegistry {
|
||||||
|
|
||||||
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
|
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
namespace Widgets {
|
namespace Widgets {
|
||||||
|
|
||||||
class Widget {
|
class Widget {
|
||||||
public:
|
public:
|
||||||
virtual ~Widget() = default;
|
virtual ~Widget() = default;
|
||||||
@ -144,6 +141,7 @@ namespace hex {
|
|||||||
private:
|
private:
|
||||||
bool m_value;
|
bool m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SliderInteger : public Widget {
|
class SliderInteger : public Widget {
|
||||||
public:
|
public:
|
||||||
SliderInteger(i32 defaultValue, i32 min, i32 max) : m_value(defaultValue), m_min(min), m_max(max) {}
|
SliderInteger(i32 defaultValue, i32 min, i32 max) : m_value(defaultValue), m_min(min), m_max(max) {}
|
||||||
@ -158,9 +156,12 @@ namespace hex {
|
|||||||
int m_value;
|
int m_value;
|
||||||
i32 m_min, m_max;
|
i32 m_min, m_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SliderFloat : public Widget {
|
class SliderFloat : public Widget {
|
||||||
public:
|
public:
|
||||||
SliderFloat(float defaultValue, float min, float max) : m_value(defaultValue), m_min(min), m_max(max) { }
|
SliderFloat(float defaultValue, float min, float max) : m_value(defaultValue), m_min(min),
|
||||||
|
m_max(max) {}
|
||||||
|
|
||||||
bool draw(const std::string& name) override;
|
bool draw(const std::string& name) override;
|
||||||
|
|
||||||
void load(const nlohmann::json& data) override;
|
void load(const nlohmann::json& data) override;
|
||||||
@ -172,6 +173,7 @@ namespace hex {
|
|||||||
float m_value;
|
float m_value;
|
||||||
float m_min, m_max;
|
float m_min, m_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ColorPicker : public Widget {
|
class ColorPicker : public Widget {
|
||||||
public:
|
public:
|
||||||
explicit ColorPicker(ImColor defaultColor);
|
explicit ColorPicker(ImColor defaultColor);
|
||||||
@ -186,9 +188,14 @@ namespace hex {
|
|||||||
private:
|
private:
|
||||||
std::array<float, 4> m_value{};
|
std::array<float, 4> m_value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class DropDown : public Widget {
|
class DropDown : public Widget {
|
||||||
public:
|
public:
|
||||||
explicit DropDown(const std::vector<std::string> &items, const std::vector<nlohmann::json> &settingsValues, const nlohmann::json &defaultItem) : m_items(items), m_settingsValues(settingsValues), m_defaultItem(defaultItem) { }
|
explicit DropDown(const std::vector<std::string>& items,
|
||||||
|
const std::vector<nlohmann::json>& settingsValues,
|
||||||
|
const nlohmann::json& defaultItem) : m_items(items),
|
||||||
|
m_settingsValues(settingsValues),
|
||||||
|
m_defaultItem(defaultItem) {}
|
||||||
|
|
||||||
bool draw(const std::string& name) override;
|
bool draw(const std::string& name) override;
|
||||||
|
|
||||||
@ -205,6 +212,7 @@ namespace hex {
|
|||||||
|
|
||||||
int m_value = -1;
|
int m_value = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextBox : public Widget {
|
class TextBox : public Widget {
|
||||||
public:
|
public:
|
||||||
explicit TextBox(std::string defaultValue) : m_value(std::move(defaultValue)) {}
|
explicit TextBox(std::string defaultValue) : m_value(std::move(defaultValue)) {}
|
||||||
@ -220,6 +228,7 @@ namespace hex {
|
|||||||
private:
|
private:
|
||||||
std::string m_value;
|
std::string m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilePicker : public Widget {
|
class FilePicker : public Widget {
|
||||||
public:
|
public:
|
||||||
bool draw(const std::string& name) override;
|
bool draw(const std::string& name) override;
|
||||||
@ -233,12 +242,9 @@ namespace hex {
|
|||||||
private:
|
private:
|
||||||
std::string m_value;
|
std::string m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
std::string unlocalizedName;
|
std::string unlocalizedName;
|
||||||
std::unique_ptr<Widgets::Widget> widget;
|
std::unique_ptr<Widgets::Widget> widget;
|
||||||
@ -260,14 +266,18 @@ namespace hex {
|
|||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
std::vector<Category>& getSettings();
|
std::vector<Category>& getSettings();
|
||||||
nlohmann::json& getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue);
|
nlohmann::json& getSetting(const std::string& unlocalizedCategory, const std::string& unlocalizedName,
|
||||||
|
const nlohmann::json& defaultValue);
|
||||||
nlohmann::json& getSettingsData();
|
nlohmann::json& getSettingsData();
|
||||||
|
|
||||||
Widgets::Widget* add(const std::string &unlocalizedCategory, const std::string &unlocalizedSubCategory, const std::string &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget);
|
Widgets::Widget* add(const std::string& unlocalizedCategory, const std::string& unlocalizedSubCategory,
|
||||||
|
const std::string& unlocalizedName, std::unique_ptr<Widgets::Widget>&& widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::derived_from<Widgets::Widget> T>
|
template <std::derived_from<Widgets::Widget> T>
|
||||||
Widgets::Widget::Interface& add(const std::string &unlocalizedCategory, const std::string &unlocalizedSubCategory, const std::string &unlocalizedName, auto && ... args) {
|
Widgets::Widget::Interface& add(const std::string& unlocalizedCategory,
|
||||||
|
const std::string& unlocalizedSubCategory,
|
||||||
|
const std::string& unlocalizedName, auto&&... args) {
|
||||||
return impl::add(
|
return impl::add(
|
||||||
unlocalizedCategory,
|
unlocalizedCategory,
|
||||||
unlocalizedSubCategory,
|
unlocalizedSubCategory,
|
||||||
@ -276,22 +286,23 @@ namespace hex {
|
|||||||
)->getInterface();
|
)->getInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedDescription);
|
void setCategoryDescription(const std::string& unlocalizedCategory,
|
||||||
|
const std::string& unlocalizedDescription);
|
||||||
|
|
||||||
nlohmann::json read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue);
|
nlohmann::json read(const std::string& unlocalizedCategory, const std::string& unlocalizedName,
|
||||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &value);
|
const nlohmann::json& defaultValue);
|
||||||
|
void write(const std::string& unlocalizedCategory, const std::string& unlocalizedName,
|
||||||
|
const nlohmann::json& value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
|
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
|
||||||
namespace CommandPaletteCommands {
|
namespace CommandPaletteCommands {
|
||||||
|
|
||||||
enum class Type : u32 {
|
enum class Type : u32 {
|
||||||
SymbolCommand,
|
SymbolCommand,
|
||||||
KeywordCommand
|
KeywordCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
struct QueryResult {
|
struct QueryResult {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::function<void(std::string)> callback;
|
std::function<void(std::string)> callback;
|
||||||
@ -318,7 +329,6 @@ namespace hex {
|
|||||||
|
|
||||||
std::vector<Entry>& getEntries();
|
std::vector<Entry>& getEntries();
|
||||||
std::vector<Handler>& getHandlers();
|
std::vector<Handler>& getHandlers();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -352,10 +362,9 @@ namespace hex {
|
|||||||
|
|
||||||
/* Pattern Language Function Registry. Allows adding of new functions that may be used inside the pattern language */
|
/* Pattern Language Function Registry. Allows adding of new functions that may be used inside the pattern language */
|
||||||
namespace PatternLanguage {
|
namespace PatternLanguage {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::IIterable&, bool,
|
||||||
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::IIterable&, bool, std::span<const pl::core::Token::Literal>)>;
|
std::span<const pl::core::Token::Literal>)>;
|
||||||
|
|
||||||
struct FunctionDefinition {
|
struct FunctionDefinition {
|
||||||
pl::api::Namespace ns;
|
pl::api::Namespace ns;
|
||||||
@ -376,7 +385,6 @@ namespace hex {
|
|||||||
std::map<std::string, Visualizer>& getInlineVisualizers();
|
std::map<std::string, Visualizer>& getInlineVisualizers();
|
||||||
std::map<std::string, pl::api::PragmaHandler>& getPragmas();
|
std::map<std::string, pl::api::PragmaHandler>& getPragmas();
|
||||||
std::vector<FunctionDefinition>& getFunctions();
|
std::vector<FunctionDefinition>& getFunctions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -412,7 +420,8 @@ namespace hex {
|
|||||||
* @param parameterCount The amount of parameters the function takes
|
* @param parameterCount The amount of parameters the function takes
|
||||||
* @param func The function callback
|
* @param func The function callback
|
||||||
*/
|
*/
|
||||||
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
|
void addFunction(const pl::api::Namespace& ns, const std::string& name,
|
||||||
|
pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback& func);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a new dangerous function to the pattern language
|
* @brief Adds a new dangerous function to the pattern language
|
||||||
@ -422,7 +431,9 @@ namespace hex {
|
|||||||
* @param parameterCount The amount of parameters the function takes
|
* @param parameterCount The amount of parameters the function takes
|
||||||
* @param func The function callback
|
* @param func The function callback
|
||||||
*/
|
*/
|
||||||
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
|
void addDangerousFunction(const pl::api::Namespace& ns, const std::string& name,
|
||||||
|
pl::api::FunctionParameterCount parameterCount,
|
||||||
|
const pl::api::FunctionCallback& func);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a new visualizer to the pattern language
|
* @brief Adds a new visualizer to the pattern language
|
||||||
@ -431,7 +442,8 @@ namespace hex {
|
|||||||
* @param function The function callback
|
* @param function The function callback
|
||||||
* @param parameterCount The amount of parameters the function takes
|
* @param parameterCount The amount of parameters the function takes
|
||||||
*/
|
*/
|
||||||
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount);
|
void addVisualizer(const std::string& name, const impl::VisualizerFunctionCallback& function,
|
||||||
|
pl::api::FunctionParameterCount parameterCount);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a new inline visualizer to the pattern language
|
* @brief Adds a new inline visualizer to the pattern language
|
||||||
@ -440,18 +452,15 @@ namespace hex {
|
|||||||
* @param function The function callback
|
* @param function The function callback
|
||||||
* @param parameterCount The amount of parameters the function takes
|
* @param parameterCount The amount of parameters the function takes
|
||||||
*/
|
*/
|
||||||
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount);
|
void addInlineVisualizer(const std::string& name, const impl::VisualizerFunctionCallback& function,
|
||||||
|
pl::api::FunctionParameterCount parameterCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* View Registry. Allows adding of new windows */
|
/* View Registry. Allows adding of new windows */
|
||||||
namespace Views {
|
namespace Views {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
void add(std::unique_ptr<View>&& view);
|
void add(std::unique_ptr<View>&& view);
|
||||||
std::map<std::string, std::unique_ptr<View>>& getEntries();
|
std::map<std::string, std::unique_ptr<View>>& getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -475,9 +484,7 @@ namespace hex {
|
|||||||
|
|
||||||
/* Tools Registry. Allows adding new entries to the tools window */
|
/* Tools Registry. Allows adding new entries to the tools window */
|
||||||
namespace Tools {
|
namespace Tools {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using Callback = std::function<void()>;
|
using Callback = std::function<void()>;
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@ -487,7 +494,6 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Entry>& getEntries();
|
std::vector<Entry>& getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -500,19 +506,17 @@ namespace hex {
|
|||||||
|
|
||||||
/* Data Inspector Registry. Allows adding of new types to the data inspector */
|
/* Data Inspector Registry. Allows adding of new types to the data inspector */
|
||||||
namespace DataInspector {
|
namespace DataInspector {
|
||||||
|
enum class NumberDisplayStyle {
|
||||||
enum class NumberDisplayStyle
|
|
||||||
{
|
|
||||||
Decimal,
|
Decimal,
|
||||||
Hexadecimal,
|
Hexadecimal,
|
||||||
Octal
|
Octal
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using DisplayFunction = std::function<std::string()>;
|
using DisplayFunction = std::function<std::string()>;
|
||||||
using EditingFunction = std::function<std::vector<u8>(std::string, std::endian)>;
|
using EditingFunction = std::function<std::vector<u8>(std::string, std::endian)>;
|
||||||
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>;
|
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8>&, std::endian,
|
||||||
|
NumberDisplayStyle)>;
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
std::string unlocalizedName;
|
std::string unlocalizedName;
|
||||||
@ -523,7 +527,6 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Entry>& getEntries();
|
std::vector<Entry>& getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -533,7 +536,9 @@ namespace hex {
|
|||||||
* @param displayGeneratorFunction The function that will be called to generate the display function
|
* @param displayGeneratorFunction The function that will be called to generate the display function
|
||||||
* @param editingFunction The function that will be called to edit the data
|
* @param editingFunction The function that will be called to edit the data
|
||||||
*/
|
*/
|
||||||
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
void add(const std::string& unlocalizedName, size_t requiredSize,
|
||||||
|
impl::GeneratorFunction displayGeneratorFunction,
|
||||||
|
std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a new entry to the data inspector
|
* @brief Adds a new entry to the data inspector
|
||||||
@ -543,14 +548,14 @@ namespace hex {
|
|||||||
* @param displayGeneratorFunction The function that will be called to generate the display function
|
* @param displayGeneratorFunction The function that will be called to generate the display function
|
||||||
* @param editingFunction The function that will be called to edit the data
|
* @param editingFunction The function that will be called to edit the data
|
||||||
*/
|
*/
|
||||||
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
void add(const std::string& unlocalizedName, size_t requiredSize, size_t maxSize,
|
||||||
|
impl::GeneratorFunction displayGeneratorFunction,
|
||||||
|
std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */
|
/* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */
|
||||||
namespace DataProcessorNode {
|
namespace DataProcessorNode {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using CreatorFunction = std::function<std::unique_ptr<dp::Node>()>;
|
using CreatorFunction = std::function<std::unique_ptr<dp::Node>()>;
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@ -578,7 +583,8 @@ namespace hex {
|
|||||||
add(impl::Entry{
|
add(impl::Entry{
|
||||||
unlocalizedCategory.c_str(),
|
unlocalizedCategory.c_str(),
|
||||||
unlocalizedName.c_str(),
|
unlocalizedName.c_str(),
|
||||||
[=, ...args = std::forward<Args>(args)] mutable {
|
[=, ...args = std::forward<Args>(args)] mutable
|
||||||
|
{
|
||||||
auto node = std::make_unique<T>(std::forward<Args>(args)...);
|
auto node = std::make_unique<T>(std::forward<Args>(args)...);
|
||||||
node->setUnlocalizedName(unlocalizedName);
|
node->setUnlocalizedName(unlocalizedName);
|
||||||
return node;
|
return node;
|
||||||
@ -590,12 +596,10 @@ namespace hex {
|
|||||||
* @brief Adds a separator to the data processor right click menu
|
* @brief Adds a separator to the data processor right click menu
|
||||||
*/
|
*/
|
||||||
void addSeparator();
|
void addSeparator();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Language Registry. Allows together with the Lang class and the _lang user defined literal to add new languages */
|
/* Language Registry. Allows together with the Lang class and the _lang user defined literal to add new languages */
|
||||||
namespace Language {
|
namespace Language {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Loads localization information from json data
|
* @brief Loads localization information from json data
|
||||||
* @param data The language data
|
* @param data The language data
|
||||||
@ -603,19 +607,14 @@ namespace hex {
|
|||||||
void addLocalization(const nlohmann::json& data);
|
void addLocalization(const nlohmann::json& data);
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
std::map<std::string, std::string>& getLanguages();
|
std::map<std::string, std::string>& getLanguages();
|
||||||
std::map<std::string, std::vector<LocalizationManager::LanguageDefinition>>& getLanguageDefinitions();
|
std::map<std::string, std::vector<LocalizationManager::LanguageDefinition>>& getLanguageDefinitions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interface Registry. Allows adding new items to various interfaces */
|
/* Interface Registry. Allows adding new items to various interfaces */
|
||||||
namespace Interface {
|
namespace Interface {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using DrawCallback = std::function<void()>;
|
using DrawCallback = std::function<void()>;
|
||||||
using MenuCallback = std::function<void()>;
|
using MenuCallback = std::function<void()>;
|
||||||
using EnabledCallback = std::function<bool()>;
|
using EnabledCallback = std::function<bool()>;
|
||||||
@ -656,7 +655,6 @@ namespace hex {
|
|||||||
std::vector<DrawCallback>& getToolbarItems();
|
std::vector<DrawCallback>& getToolbarItems();
|
||||||
std::vector<SidebarItem>& getSidebarItems();
|
std::vector<SidebarItem>& getSidebarItems();
|
||||||
std::vector<TitleBarButton>& getTitleBarButtons();
|
std::vector<TitleBarButton>& getTitleBarButtons();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -675,7 +673,9 @@ namespace hex {
|
|||||||
* @param enabledCallback The function to call to determine if the entry is enabled
|
* @param enabledCallback The function to call to determine if the entry is enabled
|
||||||
* @param view The view to use for the entry. If nullptr, the shortcut will work globally
|
* @param view The view to use for the entry. If nullptr, the shortcut will work globally
|
||||||
*/
|
*/
|
||||||
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; }, View *view = nullptr);
|
void addMenuItem(const std::vector<std::string>& unlocalizedMainMenuNames, u32 priority,
|
||||||
|
const Shortcut& shortcut, const impl::MenuCallback& function,
|
||||||
|
const impl::EnabledCallback& enabledCallback = [] { return true; }, View *view = nullptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a new main menu sub-menu entry
|
* @brief Adds a new main menu sub-menu entry
|
||||||
@ -684,7 +684,9 @@ namespace hex {
|
|||||||
* @param function The function to call when the entry is clicked
|
* @param function The function to call when the entry is clicked
|
||||||
* @param enabledCallback The function to call to determine if the entry is enabled
|
* @param enabledCallback The function to call to determine if the entry is enabled
|
||||||
*/
|
*/
|
||||||
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; });
|
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority,
|
||||||
|
const impl::MenuCallback& function,
|
||||||
|
const impl::EnabledCallback& enabledCallback = [] { return true; });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a new main menu separator
|
* @brief Adds a new main menu separator
|
||||||
@ -718,7 +720,8 @@ namespace hex {
|
|||||||
* @param function The function to call to draw the item
|
* @param function The function to call to draw the item
|
||||||
* @param enabledCallback The function
|
* @param enabledCallback The function
|
||||||
*/
|
*/
|
||||||
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback = []{ return true; });
|
void addSidebarItem(const std::string& icon, const impl::DrawCallback& function,
|
||||||
|
const impl::EnabledCallback& enabledCallback = [] { return true; });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a new title bar button
|
* @brief Adds a new title bar button
|
||||||
@ -726,22 +729,19 @@ namespace hex {
|
|||||||
* @param unlocalizedTooltip The unlocalized tooltip to use for the button
|
* @param unlocalizedTooltip The unlocalized tooltip to use for the button
|
||||||
* @param function The function to call when the button is clicked
|
* @param function The function to call when the button is clicked
|
||||||
*/
|
*/
|
||||||
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function);
|
void addTitleBarButton(const std::string& icon, const std::string& unlocalizedTooltip,
|
||||||
|
const impl::ClickCallback& function);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Provider Registry. Allows adding new data providers to be created from the UI */
|
/* Provider Registry. Allows adding new data providers to be created from the UI */
|
||||||
namespace Provider {
|
namespace Provider {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
void addProviderName(const std::string& unlocalizedName);
|
void addProviderName(const std::string& unlocalizedName);
|
||||||
|
|
||||||
using ProviderCreationFunction = prv::Provider*(*)();
|
using ProviderCreationFunction = prv::Provider*(*)();
|
||||||
void add(const std::string& typeName, ProviderCreationFunction creationFunction);
|
void add(const std::string& typeName, ProviderCreationFunction creationFunction);
|
||||||
|
|
||||||
std::vector<std::string>& getEntries();
|
std::vector<std::string>& getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -760,22 +760,19 @@ namespace hex {
|
|||||||
if (addToList)
|
if (addToList)
|
||||||
impl::addProviderName(typeName);
|
impl::addProviderName(typeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Data Formatter Registry. Allows adding formatters that are used in the Copy-As menu for example */
|
/* Data Formatter Registry. Allows adding formatters that are used in the Copy-As menu for example */
|
||||||
namespace DataFormatter {
|
namespace DataFormatter {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
|
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
std::string unlocalizedName;
|
std::string unlocalizedName;
|
||||||
Callback callback;
|
Callback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Entry>& getEntries();
|
std::vector<Entry>& getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -785,22 +782,19 @@ namespace hex {
|
|||||||
* @param callback The function to call to format the data
|
* @param callback The function to call to format the data
|
||||||
*/
|
*/
|
||||||
void add(const std::string& unlocalizedName, const impl::Callback& callback);
|
void add(const std::string& unlocalizedName, const impl::Callback& callback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* File Handler Registry. Allows adding handlers for opening files specific file types */
|
/* File Handler Registry. Allows adding handlers for opening files specific file types */
|
||||||
namespace FileHandler {
|
namespace FileHandler {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using Callback = std::function<bool(std::fs::path)>;
|
using Callback = std::function<bool(std::fs::path)>;
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
std::vector<std::string> extensions;
|
std::vector<std::string> extensions;
|
||||||
Callback callback;
|
Callback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Entry>& getEntries();
|
std::vector<Entry>& getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -809,12 +803,10 @@ namespace hex {
|
|||||||
* @param callback The function to call to handle the file
|
* @param callback The function to call to handle the file
|
||||||
*/
|
*/
|
||||||
void add(const std::vector<std::string>& extensions, const impl::Callback& callback);
|
void add(const std::vector<std::string>& extensions, const impl::Callback& callback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hex Editor Registry. Allows adding new functionality to the hex editor */
|
/* Hex Editor Registry. Allows adding new functionality to the hex editor */
|
||||||
namespace HexEditor {
|
namespace HexEditor {
|
||||||
|
|
||||||
class DataVisualizer {
|
class DataVisualizer {
|
||||||
public:
|
public:
|
||||||
DataVisualizer(std::string unlocalizedName, u16 bytesPerCell, u16 maxCharsPerCell)
|
DataVisualizer(std::string unlocalizedName, u16 bytesPerCell, u16 maxCharsPerCell)
|
||||||
@ -835,7 +827,8 @@ namespace hex {
|
|||||||
protected:
|
protected:
|
||||||
const static int TextInputFlags;
|
const static int TextInputFlags;
|
||||||
|
|
||||||
bool drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
|
bool drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data,
|
||||||
|
ImGuiInputTextFlags flags) const;
|
||||||
bool drawDefaultTextEditingTextBox(u64 address, std::string& data, ImGuiInputTextFlags flags) const;
|
bool drawDefaultTextEditingTextBox(u64 address, std::string& data, ImGuiInputTextFlags flags) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -845,11 +838,9 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
void addDataVisualizer(std::shared_ptr<DataVisualizer>&& visualizer);
|
void addDataVisualizer(std::shared_ptr<DataVisualizer>&& visualizer);
|
||||||
|
|
||||||
std::vector<std::shared_ptr<DataVisualizer>>& getVisualizers();
|
std::vector<std::shared_ptr<DataVisualizer>>& getVisualizers();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -868,12 +859,10 @@ namespace hex {
|
|||||||
* @return The data visualizer, or nullptr if it doesn't exist
|
* @return The data visualizer, or nullptr if it doesn't exist
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<DataVisualizer> getVisualizerByName(const std::string& unlocalizedName);
|
std::shared_ptr<DataVisualizer> getVisualizerByName(const std::string& unlocalizedName);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hash Registry. Allows adding new hashes to the Hash view */
|
/* Hash Registry. Allows adding new hashes to the Hash view */
|
||||||
namespace Hashes {
|
namespace Hashes {
|
||||||
|
|
||||||
class Hash {
|
class Hash {
|
||||||
public:
|
public:
|
||||||
explicit Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
explicit Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||||
@ -884,9 +873,7 @@ namespace hex {
|
|||||||
using Callback = std::function<std::vector<u8>(const Region&, prv::Provider *)>;
|
using Callback = std::function<std::vector<u8>(const Region&, prv::Provider *)>;
|
||||||
|
|
||||||
Function(Hash *type, std::string name, Callback callback)
|
Function(Hash *type, std::string name, Callback callback)
|
||||||
: m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) {
|
: m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Hash* getType() { return this->m_type; }
|
[[nodiscard]] Hash* getType() { return this->m_type; }
|
||||||
[[nodiscard]] const Hash* getType() const { return this->m_type; }
|
[[nodiscard]] const Hash* getType() const { return this->m_type; }
|
||||||
@ -932,7 +919,6 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Hash>>& getHashes();
|
std::vector<std::unique_ptr<Hash>>& getHashes();
|
||||||
|
|
||||||
void add(std::unique_ptr<Hash>&& hash);
|
void add(std::unique_ptr<Hash>&& hash);
|
||||||
@ -948,12 +934,10 @@ namespace hex {
|
|||||||
void add(Args&&... args) {
|
void add(Args&&... args) {
|
||||||
impl::add(std::make_unique<T>(std::forward<Args>(args)...));
|
impl::add(std::make_unique<T>(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Background Service Registry. Allows adding new background services */
|
/* Background Service Registry. Allows adding new background services */
|
||||||
namespace BackgroundServices {
|
namespace BackgroundServices {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
using Callback = std::function<void()>;
|
using Callback = std::function<void()>;
|
||||||
|
|
||||||
@ -971,7 +955,6 @@ namespace hex {
|
|||||||
|
|
||||||
/* Network Communication Interface Registry. Allows adding new communication interface endpoints */
|
/* Network Communication Interface Registry. Allows adding new communication interface endpoints */
|
||||||
namespace CommunicationInterface {
|
namespace CommunicationInterface {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
using NetworkCallback = std::function<nlohmann::json(const nlohmann::json&)>;
|
using NetworkCallback = std::function<nlohmann::json(const nlohmann::json&)>;
|
||||||
|
|
||||||
@ -979,14 +962,11 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void registerNetworkEndpoint(const std::string& endpoint, const impl::NetworkCallback& callback);
|
void registerNetworkEndpoint(const std::string& endpoint, const impl::NetworkCallback& callback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Experiments Registry. Allows adding new experiments */
|
/* Experiments Registry. Allows adding new experiments */
|
||||||
namespace Experiments {
|
namespace Experiments {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
struct Experiment {
|
struct Experiment {
|
||||||
std::string unlocalizedName, unlocalizedDescription;
|
std::string unlocalizedName, unlocalizedDescription;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
@ -995,16 +975,16 @@ namespace hex {
|
|||||||
std::map<std::string, Experiment>& getExperiments();
|
std::map<std::string, Experiment>& getExperiments();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addExperiment(const std::string &experimentName, const std::string &unlocalizedName, const std::string &unlocalizedDescription = "");
|
void addExperiment(const std::string& experimentName, const std::string& unlocalizedName,
|
||||||
|
const std::string& unlocalizedDescription = "");
|
||||||
void enableExperiement(const std::string& experimentName, bool enabled);
|
void enableExperiement(const std::string& experimentName, bool enabled);
|
||||||
|
|
||||||
[[nodiscard]] bool isExperimentEnabled(const std::string& experimentName);
|
[[nodiscard]] bool isExperimentEnabled(const std::string& experimentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reports Registry. Allows adding new report formatters */
|
||||||
namespace Reports {
|
namespace Reports {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using Callback = std::function<std::string(prv::Provider *)>;
|
using Callback = std::function<std::string(prv::Provider *)>;
|
||||||
|
|
||||||
struct ReportGenerator {
|
struct ReportGenerator {
|
||||||
@ -1012,12 +992,49 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<ReportGenerator>& getGenerators();
|
std::vector<ReportGenerator>& getGenerators();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addReportProvider(impl::Callback callback);
|
void addReportProvider(impl::Callback callback);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disassembler Registry. Allows adding new disassembler architectures */
|
||||||
|
namespace Disassembler {
|
||||||
|
struct Instruction {
|
||||||
|
Region region;
|
||||||
|
std::string mnemonic;
|
||||||
|
std::string operands;
|
||||||
|
|
||||||
|
std::optional<u64> jumpDestination;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Architecture {
|
||||||
|
public:
|
||||||
|
explicit Architecture(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||||
|
virtual ~Architecture() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string& getUnlocalizedName() const {
|
||||||
|
return this->m_unlocalizedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void drawConfigInterface() = 0;
|
||||||
|
virtual std::vector<Instruction> disassemble(prv::Provider *provider, const Region& region) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_unlocalizedName;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Architecture>>& getArchitectures();
|
||||||
|
|
||||||
|
void add(std::unique_ptr<Architecture> &&architecture);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::derived_from<Architecture> T>
|
||||||
|
void add(auto && ... args) {
|
||||||
|
impl::add(std::make_unique<T>(std::forward<decltype(args)>(args)...));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1116,4 +1116,23 @@ namespace hex {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace ContentRegistry::Disassembler {
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Architecture>>& getArchitectures() {
|
||||||
|
static std::vector<std::unique_ptr<Architecture>> architectures;
|
||||||
|
|
||||||
|
return architectures;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(std::unique_ptr<Architecture> &&architecture) {
|
||||||
|
getArchitectures().emplace_back(std::move(architecture));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,7 @@ namespace hex::init {
|
|||||||
|
|
||||||
ContentRegistry::Experiments::impl::getExperiments().clear();
|
ContentRegistry::Experiments::impl::getExperiments().clear();
|
||||||
ContentRegistry::Reports::impl::getGenerators().clear();
|
ContentRegistry::Reports::impl::getGenerators().clear();
|
||||||
|
ContentRegistry::Disassembler::impl::getArchitectures().clear();
|
||||||
|
|
||||||
LayoutManager::reset();
|
LayoutManager::reset();
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ add_imhex_plugin(
|
|||||||
source/content/report_generators.cpp
|
source/content/report_generators.cpp
|
||||||
source/content/init_tasks.cpp
|
source/content/init_tasks.cpp
|
||||||
source/content/fonts.cpp
|
source/content/fonts.cpp
|
||||||
|
source/content/disassemblers.cpp
|
||||||
|
|
||||||
source/content/data_processor_nodes/basic_nodes.cpp
|
source/content/data_processor_nodes/basic_nodes.cpp
|
||||||
source/content/data_processor_nodes/control_nodes.cpp
|
source/content/data_processor_nodes/control_nodes.cpp
|
||||||
|
@ -1,46 +1,36 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <hex/api/task_manager.hpp>
|
#include <hex/api/content_registry.hpp>
|
||||||
|
|
||||||
#include <hex/ui/view.hpp>
|
#include <hex/ui/view.hpp>
|
||||||
#include <ui/widgets.hpp>
|
|
||||||
|
|
||||||
#include <hex/helpers/disassembler.hpp>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace hex::plugin::builtin {
|
namespace hex::plugin::builtin {
|
||||||
|
|
||||||
struct Disassembly {
|
|
||||||
u64 address;
|
|
||||||
u64 offset;
|
|
||||||
size_t size;
|
|
||||||
std::string bytes;
|
|
||||||
std::string mnemonic;
|
|
||||||
std::string operators;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ViewDisassembler : public View::Window {
|
class ViewDisassembler : public View::Window {
|
||||||
public:
|
public:
|
||||||
explicit ViewDisassembler();
|
explicit ViewDisassembler();
|
||||||
~ViewDisassembler() override;
|
|
||||||
|
|
||||||
void drawContent() override;
|
void drawContent() override;
|
||||||
|
|
||||||
|
ImGuiWindowFlags getWindowFlags() const override {
|
||||||
|
return ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TaskHolder m_disassemblerTask;
|
struct DisassemblyLine {
|
||||||
|
ImHexApi::HexEditor::ProviderRegion region;
|
||||||
|
std::string bytes;
|
||||||
|
std::string mnemonic;
|
||||||
|
std::string operands;
|
||||||
|
|
||||||
u64 m_baseAddress = 0;
|
std::optional<u64> jumpDestination;
|
||||||
ui::RegionType m_range = ui::RegionType::EntireData;
|
ImVec2 linePos;
|
||||||
Region m_codeRegion = { 0, 0 };
|
};
|
||||||
|
|
||||||
Architecture m_architecture = Architecture::ARM;
|
void addLine(prv::Provider *provider, const ContentRegistry::Disassembler::Instruction &instruction);
|
||||||
cs_mode m_mode = cs_mode(0);
|
|
||||||
|
|
||||||
std::vector<Disassembly> m_disassembly;
|
private:
|
||||||
|
PerProvider<std::vector<DisassemblyLine>> m_lines;
|
||||||
void disassemble();
|
ContentRegistry::Disassembler::Architecture *m_currArchitecture = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
115
plugins/builtin/source/content/disassemblers.cpp
Normal file
115
plugins/builtin/source/content/disassemblers.cpp
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#include <imgui.h>
|
||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
|
||||||
|
#include <capstone/capstone.h>
|
||||||
|
#include <hex/providers/provider.hpp>
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
#include <wolv/literals.hpp>
|
||||||
|
|
||||||
|
namespace hex::plugin::builtin {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace ContentRegistry::Disassembler;
|
||||||
|
using namespace wolv::literals;
|
||||||
|
|
||||||
|
class ArchitectureCapstoneBase : public Architecture {
|
||||||
|
public:
|
||||||
|
ArchitectureCapstoneBase(const std::string &unlocalizedName, cs_arch arch) : Architecture(unlocalizedName), m_architecture(arch) { }
|
||||||
|
|
||||||
|
std::vector<Instruction> disassemble(prv::Provider *provider, const Region ®ion) override {
|
||||||
|
std::vector<Instruction> disassembly;
|
||||||
|
|
||||||
|
csh csHandle = {};
|
||||||
|
if (cs_open(this->m_architecture, CS_MODE_64, &csHandle) != CS_ERR_OK)
|
||||||
|
return {};
|
||||||
|
ON_SCOPE_EXIT { cs_close(&csHandle); };
|
||||||
|
|
||||||
|
cs_option(csHandle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL);
|
||||||
|
cs_option(csHandle, CS_OPT_DETAIL, CS_OPT_ON);
|
||||||
|
cs_option(csHandle, CS_OPT_SKIPDATA, CS_OPT_ON);
|
||||||
|
|
||||||
|
cs_insn *instruction = cs_malloc(csHandle);
|
||||||
|
ON_SCOPE_EXIT { cs_free(instruction, 1); };
|
||||||
|
|
||||||
|
std::vector<u8> bytes;
|
||||||
|
u64 prevAddress = std::numeric_limits<u64>::max();
|
||||||
|
for (u64 address = region.getStartAddress(); address < region.getEndAddress();) {
|
||||||
|
if (prevAddress == address)
|
||||||
|
break;
|
||||||
|
bytes.resize(std::min(2_MiB, (region.getEndAddress() - address) + 1));
|
||||||
|
provider->read(address, bytes.data(), bytes.size());
|
||||||
|
|
||||||
|
const u8 *code = bytes.data();
|
||||||
|
size_t size = bytes.size();
|
||||||
|
prevAddress = address;
|
||||||
|
while (cs_disasm_iter(csHandle, &code, &size, &address, instruction)) {
|
||||||
|
auto line = Instruction {
|
||||||
|
.region = { instruction->address, instruction->size },
|
||||||
|
.mnemonic = instruction->mnemonic,
|
||||||
|
.operands = instruction->op_str,
|
||||||
|
.jumpDestination = getJumpDestination(*instruction)
|
||||||
|
};
|
||||||
|
|
||||||
|
disassembly.emplace_back(std::move(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return disassembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawConfigInterface() override {
|
||||||
|
ImGui::TextUnformatted("Config Interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::optional<u64> getJumpDestination(const cs_insn &instruction) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
cs_arch m_architecture;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ArchitectureX86 : public ArchitectureCapstoneBase {
|
||||||
|
public:
|
||||||
|
ArchitectureX86() : ArchitectureCapstoneBase("x86", CS_ARCH_X86) { }
|
||||||
|
|
||||||
|
std::optional<u64> getJumpDestination(const cs_insn &instruction) override {
|
||||||
|
// Get jump destination of jumps on x86
|
||||||
|
if (instruction.id == X86_INS_JMP) {
|
||||||
|
if (instruction.detail->x86.op_count != 1)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
const auto &op = instruction.detail->x86.operands[0];
|
||||||
|
|
||||||
|
if (op.type == X86_OP_IMM)
|
||||||
|
return op.imm;
|
||||||
|
|
||||||
|
if (op.type == X86_OP_MEM && op.mem.base == X86_REG_RIP)
|
||||||
|
return instruction.address + instruction.size + op.mem.disp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get jump destination of conditional jumps on x86
|
||||||
|
if (instruction.id >= X86_INS_JAE && instruction.id <= X86_INS_JLE) {
|
||||||
|
if (instruction.detail->x86.op_count != 1)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
const auto &op = instruction.detail->x86.operands[0];
|
||||||
|
|
||||||
|
if (op.type == X86_OP_IMM)
|
||||||
|
return op.imm;
|
||||||
|
|
||||||
|
if (op.type == X86_OP_MEM && op.mem.base == X86_REG_RIP)
|
||||||
|
return instruction.address + instruction.size + op.mem.disp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerDisassemblers() {
|
||||||
|
ContentRegistry::Disassembler::add<ArchitectureX86>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,451 +1,179 @@
|
|||||||
#include "content/views/view_disassembler.hpp"
|
#include "content/views/view_disassembler.hpp"
|
||||||
|
|
||||||
#include <hex/providers/provider.hpp>
|
|
||||||
#include <hex/helpers/fmt.hpp>
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
|
||||||
#include <cstring>
|
#include <hex/providers/buffered_reader.hpp>
|
||||||
|
|
||||||
using namespace std::literals::string_literals;
|
using namespace std::literals::string_literals;
|
||||||
|
|
||||||
namespace hex::plugin::builtin {
|
namespace hex::plugin::builtin {
|
||||||
|
|
||||||
ViewDisassembler::ViewDisassembler() : View::Window("hex.builtin.view.disassembler.name") {
|
ViewDisassembler::ViewDisassembler() : View::Window("hex.builtin.view.disassembler.name") {
|
||||||
EventManager::subscribe<EventProviderDeleted>(this, [this](const auto*) {
|
|
||||||
this->m_disassembly.clear();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewDisassembler::~ViewDisassembler() {
|
void ViewDisassembler::addLine(prv::Provider *provider, const ContentRegistry::Disassembler::Instruction &instruction) {
|
||||||
EventManager::unsubscribe<EventDataChanged>(this);
|
prv::ProviderReader reader(provider);
|
||||||
EventManager::unsubscribe<EventRegionSelected>(this);
|
reader.seek(instruction.region.getStartAddress());
|
||||||
EventManager::unsubscribe<EventProviderDeleted>(this);
|
reader.setEndAddress(instruction.region.getEndAddress());
|
||||||
|
|
||||||
|
std::string bytes;
|
||||||
|
for (const auto& byte : reader) {
|
||||||
|
bytes += fmt::format("{:02X} ", byte);
|
||||||
|
}
|
||||||
|
bytes.pop_back();
|
||||||
|
|
||||||
|
this->m_lines.get(provider).emplace_back(ImHexApi::HexEditor::ProviderRegion { instruction.region, provider }, std::move(bytes), instruction.mnemonic, instruction.operands, instruction.jumpDestination, ImVec2());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewDisassembler::disassemble() {
|
static void drawJumpLine(ImVec2 start, ImVec2 end, float columnWidth, u32 slot, ImVec2, bool hovered) {
|
||||||
this->m_disassembly.clear();
|
const u32 slotCount = std::floor(std::max<float>(1.0F, columnWidth / 10_scaled));
|
||||||
|
|
||||||
this->m_disassemblerTask = TaskManager::createTask("hex.builtin.view.disassembler.disassembling", this->m_codeRegion.getSize(), [this](auto &task) {
|
if (slot >= slotCount)
|
||||||
csh capstoneHandle;
|
return;
|
||||||
cs_insn *instructions = nullptr;
|
|
||||||
|
|
||||||
cs_mode mode = this->m_mode;
|
auto drawList = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
// Create a capstone disassembler instance
|
if (start.y > end.y)
|
||||||
if (cs_open(Disassembler::toCapstoneArchitecture(this->m_architecture), mode, &capstoneHandle) == CS_ERR_OK) {
|
slot = slotCount - slot - 1;
|
||||||
|
|
||||||
// Tell capstone to skip data bytes
|
const auto width = (columnWidth / float(slotCount)) * float(slot + 1);
|
||||||
cs_option(capstoneHandle, CS_OPT_SKIPDATA, CS_OPT_ON);
|
const auto lineColor = ImColor::HSV(hovered ? 0.25F : 0.3F + (slot / float(slotCount)) * 0.7F, hovered ? 1.0F : 0.8F, hovered ? 1.0F : 0.8F);
|
||||||
|
const auto thickness = 2.0_scaled;
|
||||||
|
|
||||||
auto provider = ImHexApi::Provider::get();
|
// Draw line
|
||||||
std::vector<u8> buffer(2048, 0x00);
|
drawList->AddLine(start - ImVec2(width, 0), start, lineColor, thickness);
|
||||||
size_t size = this->m_codeRegion.getSize();
|
drawList->AddLine(end - ImVec2(width, 0), end, lineColor, thickness);
|
||||||
|
drawList->AddLine(start - ImVec2(width, 0), end - ImVec2(width, 0), lineColor, thickness);
|
||||||
|
|
||||||
// Read the data in chunks and disassemble it
|
//if (end.y >= startCursorPos.y + ImGui::GetScrollY())
|
||||||
for (u64 address = 0; address < size; address += 2048) {
|
// Draw arrow head
|
||||||
task.update(address);
|
drawList->AddLine(end + scaled({ -5, -5 }), end, lineColor, thickness);
|
||||||
|
drawList->AddLine(end + scaled({ -5, 5 }), end, lineColor, thickness);
|
||||||
// Read a chunk of data
|
|
||||||
size_t bufferSize = std::min(u64(2048), (size - address));
|
|
||||||
provider->read(this->m_codeRegion.getStartAddress() + address, buffer.data(), bufferSize);
|
|
||||||
|
|
||||||
// Ask capstone to disassemble the data
|
|
||||||
size_t instructionCount = cs_disasm(capstoneHandle, buffer.data(), bufferSize, this->m_baseAddress + address, 0, &instructions);
|
|
||||||
if (instructionCount == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Reserve enough space for the disassembly
|
|
||||||
this->m_disassembly.reserve(this->m_disassembly.size() + instructionCount);
|
|
||||||
|
|
||||||
// Convert the capstone instructions to our disassembly format
|
|
||||||
u64 usedBytes = 0;
|
|
||||||
for (u32 i = 0; i < instructionCount; i++) {
|
|
||||||
const auto &instr = instructions[i];
|
|
||||||
Disassembly disassembly = { };
|
|
||||||
disassembly.address = instr.address;
|
|
||||||
disassembly.offset = this->m_codeRegion.getStartAddress() + address + usedBytes;
|
|
||||||
disassembly.size = instr.size;
|
|
||||||
disassembly.mnemonic = instr.mnemonic;
|
|
||||||
disassembly.operators = instr.op_str;
|
|
||||||
|
|
||||||
for (u16 j = 0; j < instr.size; j++)
|
|
||||||
disassembly.bytes += hex::format("{0:02X} ", instr.bytes[j]);
|
|
||||||
disassembly.bytes.pop_back();
|
|
||||||
|
|
||||||
this->m_disassembly.push_back(disassembly);
|
|
||||||
|
|
||||||
usedBytes += instr.size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If capstone couldn't disassemble all bytes in the buffer, we might have cut off an instruction
|
|
||||||
// Adjust the address,so it's being disassembled when we read the next chunk
|
|
||||||
if (instructionCount < bufferSize)
|
|
||||||
address -= (bufferSize - usedBytes);
|
|
||||||
|
|
||||||
// Clean up the capstone instructions
|
|
||||||
cs_free(instructions, instructionCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
cs_close(&capstoneHandle);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ViewDisassembler::drawContent() {
|
void ViewDisassembler::drawContent() {
|
||||||
auto provider = ImHexApi::Provider::get();
|
const auto &architectures = ContentRegistry::Disassembler::impl::getArchitectures();
|
||||||
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
|
if (this->m_currArchitecture == nullptr) {
|
||||||
ImGuiExt::Header("hex.builtin.view.disassembler.position"_lang, true);
|
this->m_currArchitecture = architectures.front().get();
|
||||||
|
|
||||||
// Draw base address input
|
|
||||||
ImGuiExt::InputHexadecimal("hex.builtin.view.disassembler.base"_lang, &this->m_baseAddress, ImGuiInputTextFlags_CharsHexadecimal);
|
|
||||||
|
|
||||||
// Draw region selection picker
|
|
||||||
ui::regionSelectionPicker(&this->m_codeRegion, provider, &this->m_range);
|
|
||||||
|
|
||||||
// Draw settings
|
|
||||||
{
|
|
||||||
ImGuiExt::Header("hex.builtin.common.settings"_lang);
|
|
||||||
|
|
||||||
// Draw architecture selector
|
|
||||||
if (ImGui::Combo("hex.builtin.view.disassembler.arch"_lang, reinterpret_cast<int *>(&this->m_architecture), Disassembler::ArchitectureNames.data(), Disassembler::getArchitectureSupportedCount()))
|
|
||||||
this->m_mode = cs_mode(0);
|
|
||||||
|
|
||||||
// Draw sub-settings for each architecture
|
|
||||||
if (ImGuiExt::BeginBox()) {
|
|
||||||
|
|
||||||
// Draw endian radio buttons. This setting is available for all architectures
|
|
||||||
static int littleEndian = true;
|
|
||||||
ImGui::RadioButton("hex.builtin.common.little_endian"_lang, &littleEndian, true);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.common.big_endian"_lang, &littleEndian, false);
|
|
||||||
|
|
||||||
ImGui::NewLine();
|
|
||||||
|
|
||||||
// Draw architecture specific settings
|
|
||||||
switch (this->m_architecture) {
|
|
||||||
case Architecture::ARM:
|
|
||||||
{
|
|
||||||
static int mode = CS_MODE_ARM;
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.arm.arm"_lang, &mode, CS_MODE_ARM);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.arm.thumb"_lang, &mode, CS_MODE_THUMB);
|
|
||||||
|
|
||||||
static int extraMode = 0;
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.arm.default"_lang, &extraMode, 0);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.arm.cortex_m"_lang, &extraMode, CS_MODE_MCLASS);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.arm.armv8"_lang, &extraMode, CS_MODE_V8);
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(mode | extraMode);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case Architecture::MIPS:
|
|
||||||
{
|
|
||||||
static int mode = CS_MODE_MIPS32;
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips32"_lang, &mode, CS_MODE_MIPS32);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips64"_lang, &mode, CS_MODE_MIPS64);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips32R6"_lang, &mode, CS_MODE_MIPS32R6);
|
|
||||||
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips2"_lang, &mode, CS_MODE_MIPS2);
|
ImGui::BeginDisabled(!this->m_lines->empty());
|
||||||
ImGui::SameLine();
|
if (ImGui::BeginCombo("##architectures", Lang(this->m_currArchitecture->getUnlocalizedName()))) {
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips3"_lang, &mode, CS_MODE_MIPS3);
|
for (const auto &architecture : architectures) {
|
||||||
|
if (ImGui::Selectable(Lang(architecture->getUnlocalizedName()))) {
|
||||||
static bool microMode;
|
this->m_currArchitecture = architecture.get();
|
||||||
ImGui::Checkbox("hex.builtin.view.disassembler.mips.micro"_lang, µMode);
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(mode | (microMode ? CS_MODE_MICRO : cs_mode(0)));
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case Architecture::X86:
|
|
||||||
{
|
|
||||||
static int mode = CS_MODE_32;
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.16bit"_lang, &mode, CS_MODE_16);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.32bit"_lang, &mode, CS_MODE_32);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.64bit"_lang, &mode, CS_MODE_64);
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(mode);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case Architecture::PPC:
|
|
||||||
{
|
|
||||||
static int mode = CS_MODE_32;
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.32bit"_lang, &mode, CS_MODE_32);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.64bit"_lang, &mode, CS_MODE_64);
|
|
||||||
|
|
||||||
static bool qpx = false;
|
|
||||||
ImGui::Checkbox("hex.builtin.view.disassembler.ppc.qpx"_lang, &qpx);
|
|
||||||
|
|
||||||
#if CS_API_MAJOR >= 5
|
|
||||||
static bool spe = false;
|
|
||||||
ImGui::Checkbox("hex.builtin.view.disassembler.ppc.spe"_lang, &spe);
|
|
||||||
static bool booke = false;
|
|
||||||
ImGui::Checkbox("hex.builtin.view.disassembler.ppc.booke"_lang, &booke);
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(mode | (qpx ? CS_MODE_QPX : cs_mode(0)) | (spe ? CS_MODE_SPE : cs_mode(0)) | (booke ? CS_MODE_BOOKE : cs_mode(0)));
|
|
||||||
#else
|
|
||||||
this->m_mode = cs_mode(mode | (qpx ? CS_MODE_QPX : cs_mode(0)));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Architecture::SPARC:
|
|
||||||
{
|
|
||||||
static bool v9Mode = false;
|
|
||||||
ImGui::Checkbox("hex.builtin.view.disassembler.sparc.v9"_lang, &v9Mode);
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(v9Mode ? CS_MODE_V9 : cs_mode(0));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#if CS_API_MAJOR >= 5
|
|
||||||
case Architecture::RISCV:
|
|
||||||
{
|
|
||||||
static int mode = CS_MODE_RISCV32;
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.32bit"_lang, &mode, CS_MODE_RISCV32);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.64bit"_lang, &mode, CS_MODE_RISCV64);
|
|
||||||
|
|
||||||
static bool compressed = false;
|
|
||||||
ImGui::Checkbox("hex.builtin.view.disassembler.riscv.compressed"_lang, &compressed);
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(mode | (compressed ? CS_MODE_RISCVC : cs_mode(0)));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case Architecture::M68K:
|
|
||||||
{
|
|
||||||
static int selectedMode = 0;
|
|
||||||
|
|
||||||
std::pair<const char *, cs_mode> modes[] = {
|
|
||||||
{"hex.builtin.view.disassembler.m68k.000"_lang, CS_MODE_M68K_000},
|
|
||||||
{ "hex.builtin.view.disassembler.m68k.010"_lang, CS_MODE_M68K_010},
|
|
||||||
{ "hex.builtin.view.disassembler.m68k.020"_lang, CS_MODE_M68K_020},
|
|
||||||
{ "hex.builtin.view.disassembler.m68k.030"_lang, CS_MODE_M68K_030},
|
|
||||||
{ "hex.builtin.view.disassembler.m68k.040"_lang, CS_MODE_M68K_040},
|
|
||||||
{ "hex.builtin.view.disassembler.m68k.060"_lang, CS_MODE_M68K_060},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectedMode].first)) {
|
|
||||||
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
|
|
||||||
if (ImGui::Selectable(modes[i].first))
|
|
||||||
selectedMode = i;
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_mode = cs_mode(modes[selectedMode].second);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Architecture::M680X:
|
|
||||||
{
|
|
||||||
static int selectedMode = 0;
|
|
||||||
|
|
||||||
std::pair<const char *, cs_mode> modes[] = {
|
|
||||||
{"hex.builtin.view.disassembler.m680x.6301"_lang, CS_MODE_M680X_6301 },
|
|
||||||
{ "hex.builtin.view.disassembler.m680x.6309"_lang, CS_MODE_M680X_6309 },
|
|
||||||
{ "hex.builtin.view.disassembler.m680x.6800"_lang, CS_MODE_M680X_6800 },
|
|
||||||
{ "hex.builtin.view.disassembler.m680x.6801"_lang, CS_MODE_M680X_6801 },
|
|
||||||
{ "hex.builtin.view.disassembler.m680x.6805"_lang, CS_MODE_M680X_6805 },
|
|
||||||
{ "hex.builtin.view.disassembler.m680x.6808"_lang, CS_MODE_M680X_6808 },
|
|
||||||
{ "hex.builtin.view.disassembler.m680x.6809"_lang, CS_MODE_M680X_6809 },
|
|
||||||
{ "hex.builtin.view.disassembler.m680x.6811"_lang, CS_MODE_M680X_6811 },
|
|
||||||
{ "hex.builtin.view.disassembler.m680x.cpu12"_lang, CS_MODE_M680X_CPU12},
|
|
||||||
{ "hex.builtin.view.disassembler.m680x.hcs08"_lang, CS_MODE_M680X_HCS08},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectedMode].first)) {
|
|
||||||
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
|
|
||||||
if (ImGui::Selectable(modes[i].first))
|
|
||||||
selectedMode = i;
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(modes[selectedMode].second);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#if CS_API_MAJOR >= 5
|
|
||||||
case Architecture::MOS65XX:
|
|
||||||
{
|
|
||||||
static int selectedMode = 0;
|
|
||||||
|
|
||||||
std::pair<const char *, cs_mode> modes[] = {
|
|
||||||
{"hex.builtin.view.disassembler.mos65xx.6502"_lang, CS_MODE_MOS65XX_6502 },
|
|
||||||
{ "hex.builtin.view.disassembler.mos65xx.65c02"_lang, CS_MODE_MOS65XX_65C02 },
|
|
||||||
{ "hex.builtin.view.disassembler.mos65xx.w65c02"_lang, CS_MODE_MOS65XX_W65C02 },
|
|
||||||
{ "hex.builtin.view.disassembler.mos65xx.65816"_lang, CS_MODE_MOS65XX_65816 },
|
|
||||||
{ "hex.builtin.view.disassembler.mos65xx.65816_long_m"_lang, CS_MODE_MOS65XX_65816_LONG_M },
|
|
||||||
{ "hex.builtin.view.disassembler.mos65xx.65816_long_x"_lang, CS_MODE_MOS65XX_65816_LONG_X },
|
|
||||||
{ "hex.builtin.view.disassembler.mos65xx.65816_long_mx"_lang, CS_MODE_MOS65XX_65816_LONG_MX},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectedMode].first)) {
|
|
||||||
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
|
|
||||||
if (ImGui::Selectable(modes[i].first))
|
|
||||||
selectedMode = i;
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(modes[selectedMode].second);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
#if CS_API_MAJOR >= 5
|
|
||||||
case Architecture::BPF:
|
|
||||||
{
|
|
||||||
static int mode = CS_MODE_BPF_CLASSIC;
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.bpf.classic"_lang, &mode, CS_MODE_BPF_CLASSIC);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::RadioButton("hex.builtin.view.disassembler.bpf.extended"_lang, &mode, CS_MODE_BPF_EXTENDED);
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(mode);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Architecture::SH:
|
|
||||||
{
|
|
||||||
static u32 selectionMode = 0;
|
|
||||||
static bool fpu = false;
|
|
||||||
static bool dsp = false;
|
|
||||||
|
|
||||||
std::pair<const char*, cs_mode> modes[] = {
|
|
||||||
{ "hex.builtin.view.disassembler.sh.sh2"_lang, CS_MODE_SH2 },
|
|
||||||
{ "hex.builtin.view.disassembler.sh.sh2a"_lang, CS_MODE_SH2A },
|
|
||||||
{ "hex.builtin.view.disassembler.sh.sh3"_lang, CS_MODE_SH3 },
|
|
||||||
{ "hex.builtin.view.disassembler.sh.sh4"_lang, CS_MODE_SH4 },
|
|
||||||
{ "hex.builtin.view.disassembler.sh.sh4a"_lang, CS_MODE_SH4A },
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectionMode].first)) {
|
|
||||||
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
|
|
||||||
if (ImGui::Selectable(modes[i].first))
|
|
||||||
selectionMode = i;
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Checkbox("hex.builtin.view.disassembler.sh.fpu"_lang, &fpu);
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Checkbox("hex.builtin.view.disassembler.sh.dsp"_lang, &dsp);
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(modes[selectionMode].second | (fpu ? CS_MODE_SHFPU : cs_mode(0)) | (dsp ? CS_MODE_SHDSP : cs_mode(0)));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Architecture::TRICORE:
|
|
||||||
{
|
|
||||||
static u32 selectionMode = 0;
|
|
||||||
|
|
||||||
std::pair<const char*, cs_mode> modes[] = {
|
|
||||||
{ "hex.builtin.view.disassembler.tricore.110"_lang, CS_MODE_TRICORE_110 },
|
|
||||||
{ "hex.builtin.view.disassembler.tricore.120"_lang, CS_MODE_TRICORE_120 },
|
|
||||||
{ "hex.builtin.view.disassembler.tricore.130"_lang, CS_MODE_TRICORE_130 },
|
|
||||||
{ "hex.builtin.view.disassembler.tricore.131"_lang, CS_MODE_TRICORE_131 },
|
|
||||||
{ "hex.builtin.view.disassembler.tricore.160"_lang, CS_MODE_TRICORE_160 },
|
|
||||||
{ "hex.builtin.view.disassembler.tricore.161"_lang, CS_MODE_TRICORE_161 },
|
|
||||||
{ "hex.builtin.view.disassembler.tricore.162"_lang, CS_MODE_TRICORE_162 },
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ImGui::BeginCombo("hex.builtin.view.disassembler.settings.mode"_lang, modes[selectionMode].first)) {
|
|
||||||
for (u32 i = 0; i < IM_ARRAYSIZE(modes); i++) {
|
|
||||||
if (ImGui::Selectable(modes[i].first))
|
|
||||||
selectionMode = i;
|
|
||||||
}
|
|
||||||
ImGui::EndCombo();
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m_mode = cs_mode(modes[selectionMode].second);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Architecture::WASM:
|
|
||||||
#endif
|
|
||||||
case Architecture::EVM:
|
|
||||||
case Architecture::TMS320C64X:
|
|
||||||
case Architecture::ARM64:
|
|
||||||
case Architecture::SYSZ:
|
|
||||||
case Architecture::XCORE:
|
|
||||||
this->m_mode = cs_mode(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiExt::EndBox();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw disassemble button
|
|
||||||
ImGui::BeginDisabled(this->m_disassemblerTask.isRunning());
|
|
||||||
{
|
|
||||||
if (ImGui::Button("hex.builtin.view.disassembler.disassemble"_lang))
|
|
||||||
this->disassemble();
|
|
||||||
}
|
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
// Draw a spinner if the disassembler is running
|
|
||||||
if (this->m_disassemblerTask.isRunning()) {
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGuiExt::TextSpinner("hex.builtin.view.disassembler.disassembling"_lang);
|
|
||||||
|
if (this->m_lines->empty()) {
|
||||||
|
auto provider = ImHexApi::Provider::get();
|
||||||
|
if (ImGuiExt::DimmedButton("Disassemble", ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
|
||||||
|
auto disassembly = this->m_currArchitecture->disassemble(provider, ImHexApi::HexEditor::getSelection().value());
|
||||||
|
|
||||||
|
for (const auto &instruction : disassembly)
|
||||||
|
this->addLine(provider, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::NewLine();
|
ImGuiExt::BeginSubWindow("Config");
|
||||||
|
{
|
||||||
|
this->m_currArchitecture->drawConfigInterface();
|
||||||
|
}
|
||||||
|
ImGuiExt::EndSubWindow();
|
||||||
|
} else {
|
||||||
|
if (ImGuiExt::DimmedButton("Reset", ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
|
||||||
|
this->m_lines->clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::TextUnformatted("hex.builtin.view.disassembler.disassembly.title"_lang);
|
if (ImGui::BeginTable("##disassembly", 4, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable, ImGui::GetContentRegionAvail())) {
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
// Draw disassembly table
|
|
||||||
if (ImGui::BeginTable("##disassembly", 4, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) {
|
|
||||||
ImGui::TableSetupScrollFreeze(0, 1);
|
ImGui::TableSetupScrollFreeze(0, 1);
|
||||||
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.address"_lang);
|
ImGui::TableSetupColumn("##jumps");
|
||||||
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.offset"_lang);
|
ImGui::TableSetupColumn("##address", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize, 80_scaled);
|
||||||
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.bytes"_lang);
|
ImGui::TableSetupColumn("##bytes", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize, 80_scaled);
|
||||||
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.title"_lang);
|
ImGui::TableSetupColumn("##instruction", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_NoResize);
|
||||||
|
|
||||||
if (!this->m_disassemblerTask.isRunning()) {
|
|
||||||
ImGuiListClipper clipper;
|
|
||||||
clipper.Begin(this->m_disassembly.size());
|
|
||||||
|
|
||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
|
ImGuiListClipper clipper;
|
||||||
|
clipper.Begin(this->m_lines->size(), ImGui::GetTextLineHeightWithSpacing());
|
||||||
|
|
||||||
|
int processingStart = 0, processingEnd = 0;
|
||||||
|
|
||||||
|
auto startCursorPos = ImGui::GetCursorScreenPos();
|
||||||
|
float jumpColumnWidth = 0.0F;
|
||||||
|
std::optional<u64> hoveredAddress;
|
||||||
while (clipper.Step()) {
|
while (clipper.Step()) {
|
||||||
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
|
processingStart = clipper.DisplayStart;
|
||||||
const auto &instruction = this->m_disassembly[i];
|
processingEnd = clipper.DisplayEnd;
|
||||||
|
for (auto i = processingStart; i < processingEnd; i += 1) {
|
||||||
|
auto &line = this->m_lines->at(i);
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
|
||||||
|
|
||||||
// Draw a selectable label for the address
|
auto height = ImGui::CalcTextSize(line.bytes.c_str(), nullptr, false, 80_scaled).y;
|
||||||
ImGui::PushID(i);
|
|
||||||
if (ImGui::Selectable("##DisassemblyLine", false, ImGuiSelectableFlags_SpanAllColumns)) {
|
ImGui::TableNextColumn();
|
||||||
ImHexApi::HexEditor::setSelection(instruction.offset, instruction.size);
|
{
|
||||||
|
// Reserve some space to draw the jump lines later
|
||||||
|
|
||||||
|
// Remember the position of the line so we can draw the jump lines later
|
||||||
|
jumpColumnWidth = ImGui::GetContentRegionAvail().x;
|
||||||
|
line.linePos = ImGui::GetCursorScreenPos() + ImVec2(jumpColumnWidth, height / 2);
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
|
||||||
|
|
||||||
// Draw instruction address
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGuiExt::TextFormatted("0x{0:X}", instruction.address);
|
|
||||||
|
|
||||||
// Draw instruction offset
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGuiExt::TextFormatted("0x{0:X}", instruction.offset);
|
if (ImGui::Selectable(hex::format("0x{:08X}", line.region.getStartAddress()).c_str(), false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(0, height))) {
|
||||||
|
ImHexApi::HexEditor::setSelection(line.region);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw instruction bytes
|
if (ImGui::IsItemHovered())
|
||||||
ImGui::TableNextColumn();
|
hoveredAddress = line.region.getStartAddress();
|
||||||
ImGui::TextUnformatted(instruction.bytes.c_str());
|
|
||||||
|
|
||||||
// Draw instruction mnemonic and operands
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGuiExt::TextFormattedColored(ImColor(0xFFD69C56), "{}", instruction.mnemonic);
|
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_Highlight));
|
||||||
ImGui::SameLine();
|
ImGuiExt::TextFormattedWrapped("{}", line.bytes);
|
||||||
ImGui::TextUnformatted(instruction.operators.c_str());
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGuiExt::TextFormattedColored(ImGui::GetColorU32(ImGuiCol_HeaderActive), "{} ", line.mnemonic);
|
||||||
|
ImGui::SameLine(0, 0);
|
||||||
|
ImGuiExt::TextFormatted("{}", line.operands);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clipper.End();
|
// Draw jump arrows
|
||||||
|
{
|
||||||
|
std::list<u64> destinations;
|
||||||
|
for (auto sourceLineIndex = processingStart; sourceLineIndex < processingEnd; sourceLineIndex += 1) {
|
||||||
|
const auto &sourceLine = this->m_lines->at(sourceLineIndex);
|
||||||
|
|
||||||
|
if (sourceLine.jumpDestination.has_value()) {
|
||||||
|
for (auto destinationLineIndex = processingStart; destinationLineIndex < processingEnd; destinationLineIndex += 1) {
|
||||||
|
const auto &destinationLine = this->m_lines->at(destinationLineIndex);
|
||||||
|
|
||||||
|
if (destinationLine.region.getStartAddress() == sourceLine.jumpDestination.value()) {
|
||||||
|
drawJumpLine(sourceLine.linePos, destinationLine.linePos, jumpColumnWidth, destinations.size(), startCursorPos, hoveredAddress == sourceLine.region.getStartAddress() || hoveredAddress == destinationLine.region.getStartAddress());
|
||||||
|
destinations.push_back(destinationLine.region.getStartAddress());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::erase_if(destinations, [&](u64 address) {
|
||||||
|
return sourceLine.region.getStartAddress() == address;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ namespace hex::plugin::builtin {
|
|||||||
void registerProjectHandlers();
|
void registerProjectHandlers();
|
||||||
void registerAchievements();
|
void registerAchievements();
|
||||||
void registerReportGenerators();
|
void registerReportGenerators();
|
||||||
|
void registerDisassemblers();
|
||||||
|
|
||||||
void addFooterItems();
|
void addFooterItems();
|
||||||
void addTitleBarButtons();
|
void addTitleBarButtons();
|
||||||
@ -106,6 +107,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
|||||||
registerCommandForwarders();
|
registerCommandForwarders();
|
||||||
registerAchievements();
|
registerAchievements();
|
||||||
registerReportGenerators();
|
registerReportGenerators();
|
||||||
|
registerDisassemblers();
|
||||||
|
|
||||||
addFooterItems();
|
addFooterItems();
|
||||||
addTitleBarButtons();
|
addTitleBarButtons();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user