1
0
mirror of synced 2025-02-08 23:09:36 +01:00

feat: Initial implementation of improved disassembler

This commit is contained in:
WerWolv 2023-12-04 11:46:35 +01:00
parent f71fa2f704
commit 2a55cd8a4f
9 changed files with 519 additions and 646 deletions

View File

@ -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,19 +43,16 @@ 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;
virtual bool draw(const std::string &name) = 0; virtual bool draw(const std::string& name) = 0;
virtual void load(const nlohmann::json &data) = 0; virtual void load(const nlohmann::json& data) = 0;
virtual nlohmann::json store() = 0; virtual nlohmann::json store() = 0;
class Interface { class Interface {
@ -80,7 +77,7 @@ namespace hex {
return *this; return *this;
} }
Interface& setTooltip(const std::string &tooltip) { Interface& setTooltip(const std::string& tooltip) {
this->m_tooltip = tooltip; this->m_tooltip = tooltip;
return *this; return *this;
@ -130,13 +127,13 @@ namespace hex {
Interface m_interface = Interface(this); Interface m_interface = Interface(this);
}; };
class Checkbox : public Widget { class Checkbox : public Widget {
public: public:
explicit Checkbox(bool defaultValue) : m_value(defaultValue) { } explicit Checkbox(bool defaultValue) : m_value(defaultValue) {}
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;
nlohmann::json store() override; nlohmann::json store() override;
[[nodiscard]] bool isChecked() const { return this->m_value; } [[nodiscard]] bool isChecked() const { return this->m_value; }
@ -144,12 +141,13 @@ 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) {}
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;
nlohmann::json store() override; nlohmann::json store() override;
[[nodiscard]] i32 getValue() const { return this->m_value; } [[nodiscard]] i32 getValue() const { return this->m_value; }
@ -158,12 +156,15 @@ namespace hex {
int m_value; int m_value;
i32 m_min, m_max; i32 m_min, m_max;
}; };
class SliderFloat : public Widget {
public:
SliderFloat(float defaultValue, float min, float max) : m_value(defaultValue), m_min(min), m_max(max) { }
bool draw(const std::string &name) override;
void load(const nlohmann::json &data) override; class SliderFloat : public Widget {
public:
SliderFloat(float defaultValue, float min, float max) : m_value(defaultValue), m_min(min),
m_max(max) {}
bool draw(const std::string& name) override;
void load(const nlohmann::json& data) override;
nlohmann::json store() override; nlohmann::json store() override;
[[nodiscard]] float getValue() const { return this->m_value; } [[nodiscard]] float getValue() const { return this->m_value; }
@ -172,13 +173,14 @@ 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);
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;
nlohmann::json store() override; nlohmann::json store() override;
[[nodiscard]] ImColor getColor() const; [[nodiscard]] ImColor getColor() const;
@ -186,13 +188,18 @@ 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;
void load(const nlohmann::json &data) override; void load(const nlohmann::json& data) override;
nlohmann::json store() override; nlohmann::json store() override;
[[nodiscard]] [[nodiscard]]
@ -205,13 +212,14 @@ 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)) {}
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;
nlohmann::json store() override; nlohmann::json store() override;
[[nodiscard]] [[nodiscard]]
@ -220,11 +228,12 @@ namespace hex {
private: private:
std::string m_value; std::string m_value;
}; };
class FilePicker : public Widget {
public:
bool draw(const std::string &name) override;
void load(const nlohmann::json &data) override; class FilePicker : public Widget {
public:
bool draw(const std::string& name) override;
void load(const nlohmann::json& data) override;
nlohmann::json store() override; nlohmann::json store() override;
[[nodiscard]] [[nodiscard]]
@ -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;
@ -259,39 +265,44 @@ namespace hex {
void store(); void store();
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,
nlohmann::json &getSettingsData(); const nlohmann::json& defaultValue);
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,
unlocalizedName, unlocalizedName,
std::make_unique<T>(std::forward<decltype(args)>(args)...) std::make_unique<T>(std::forward<decltype(args)>(args)...)
)->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;
@ -299,7 +310,7 @@ namespace hex {
using DisplayCallback = std::function<std::string(std::string)>; using DisplayCallback = std::function<std::string(std::string)>;
using ExecuteCallback = std::function<void(std::string)>; using ExecuteCallback = std::function<void(std::string)>;
using QueryCallback = std::function<std::vector<QueryResult>(std::string)>; using QueryCallback = std::function<std::vector<QueryResult>(std::string)>;
struct Entry { struct Entry {
Type type; Type type;
@ -316,9 +327,8 @@ namespace hex {
DisplayCallback displayCallback; DisplayCallback displayCallback;
}; };
std::vector<Entry> &getEntries(); std::vector<Entry>& getEntries();
std::vector<Handler> &getHandlers(); std::vector<Handler>& getHandlers();
} }
/** /**
@ -331,10 +341,10 @@ namespace hex {
*/ */
void add( void add(
Type type, Type type,
const std::string &command, const std::string& command,
const std::string &unlocalizedDescription, const std::string& unlocalizedDescription,
const impl::DisplayCallback &displayCallback, const impl::DisplayCallback& displayCallback,
const impl::ExecuteCallback &executeCallback = [](auto) {}); const impl::ExecuteCallback& executeCallback = [](auto) {});
/** /**
* @brief Adds a new command handler to the command palette * @brief Adds a new command handler to the command palette
@ -345,17 +355,16 @@ namespace hex {
*/ */
void addHandler( void addHandler(
Type type, Type type,
const std::string &command, const std::string& command,
const impl::QueryCallback &queryCallback, const impl::QueryCallback& queryCallback,
const impl::DisplayCallback &displayCallback); const impl::DisplayCallback& displayCallback);
} }
/* 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;
@ -372,11 +381,10 @@ namespace hex {
VisualizerFunctionCallback callback; VisualizerFunctionCallback callback;
}; };
std::map<std::string, Visualizer> &getVisualizers(); std::map<std::string, Visualizer>& getVisualizers();
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();
} }
/** /**
@ -396,14 +404,14 @@ namespace hex {
* @param runtime The pattern language runtime to configure * @param runtime The pattern language runtime to configure
* @param provider The provider to use for data access * @param provider The provider to use for data access
*/ */
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider); void configureRuntime(pl::PatternLanguage& runtime, prv::Provider *provider);
/** /**
* @brief Adds a new pragma to the pattern language * @brief Adds a new pragma to the pattern language
* @param name The name of the pragma * @param name The name of the pragma
* @param handler The handler that will be called when the pragma is encountered * @param handler The handler that will be called when the pragma is encountered
*/ */
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler); void addPragma(const std::string& name, const pl::api::PragmaHandler& handler);
/** /**
* @brief Adds a new function to the pattern language * @brief Adds a new function to the pattern language
@ -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();
} }
/** /**
@ -460,8 +469,8 @@ namespace hex {
* @tparam Args Arguments types * @tparam Args Arguments types
* @param args Arguments passed to the constructor of the view * @param args Arguments passed to the constructor of the view
*/ */
template<std::derived_from<View> T, typename... Args> template <std::derived_from<View> T, typename... Args>
void add(Args &&...args) { void add(Args&&... args) {
return impl::add(std::make_unique<T>(std::forward<Args>(args)...)); return impl::add(std::make_unique<T>(std::forward<Args>(args)...));
} }
@ -470,14 +479,12 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the view * @param unlocalizedName The unlocalized name of the view
* @return The view if it exists, nullptr otherwise * @return The view if it exists, nullptr otherwise
*/ */
View* getViewByName(const std::string &unlocalizedName); View* getViewByName(const std::string& unlocalizedName);
} }
/* 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 {
@ -486,8 +493,7 @@ namespace hex {
bool detached; bool detached;
}; };
std::vector<Entry> &getEntries(); std::vector<Entry>& getEntries();
} }
/** /**
@ -495,24 +501,22 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the tool * @param unlocalizedName The unlocalized name of the tool
* @param function The function that will be called to draw the tool * @param function The function that will be called to draw the tool
*/ */
void add(const std::string &unlocalizedName, const impl::Callback &function); void add(const std::string& unlocalizedName, const impl::Callback& function);
} }
/* 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,
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>; NumberDisplayStyle)>;
struct Entry { struct Entry {
std::string unlocalizedName; std::string unlocalizedName;
@ -522,8 +526,7 @@ namespace hex {
std::optional<EditingFunction> editingFunction; std::optional<EditingFunction> editingFunction;
}; };
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 {
@ -559,9 +564,9 @@ namespace hex {
CreatorFunction creatorFunction; CreatorFunction creatorFunction;
}; };
void add(const Entry &entry); void add(const Entry& entry);
std::vector<Entry> &getEntries(); std::vector<Entry>& getEntries();
} }
@ -573,12 +578,13 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the node * @param unlocalizedName The unlocalized name of the node
* @param args Arguments passed to the constructor of the node * @param args Arguments passed to the constructor of the node
*/ */
template<std::derived_from<dp::Node> T, typename... Args> template <std::derived_from<dp::Node> T, typename... Args>
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) { void add(const std::string& unlocalizedCategory, const std::string& unlocalizedName, Args&&... args) {
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,36 +596,29 @@ 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
*/ */
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()>; using ClickCallback = std::function<void()>;
using ClickCallback = std::function<void()>;
struct MainMenuItem { struct MainMenuItem {
std::string unlocalizedName; std::string unlocalizedName;
@ -648,15 +647,14 @@ namespace hex {
constexpr static auto SeparatorValue = "$SEPARATOR$"; constexpr static auto SeparatorValue = "$SEPARATOR$";
constexpr static auto SubMenuValue = "$SUBMENU$"; constexpr static auto SubMenuValue = "$SUBMENU$";
std::multimap<u32, MainMenuItem> &getMainMenuItems(); std::multimap<u32, MainMenuItem>& getMainMenuItems();
std::multimap<u32, MenuItem> &getMenuItems(); std::multimap<u32, MenuItem>& getMenuItems();
std::vector<DrawCallback> &getWelcomeScreenEntries();
std::vector<DrawCallback> &getFooterItems();
std::vector<DrawCallback> &getToolbarItems();
std::vector<SidebarItem> &getSidebarItems();
std::vector<TitleBarButton> &getTitleBarButtons();
std::vector<DrawCallback>& getWelcomeScreenEntries();
std::vector<DrawCallback>& getFooterItems();
std::vector<DrawCallback>& getToolbarItems();
std::vector<SidebarItem>& getSidebarItems();
std::vector<TitleBarButton>& getTitleBarButtons();
} }
/** /**
@ -664,7 +662,7 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the entry * @param unlocalizedName The unlocalized name of the entry
* @param priority The priority of the entry. Lower values are displayed first * @param priority The priority of the entry. Lower values are displayed first
*/ */
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority); void registerMainMenuItem(const std::string& unlocalizedName, u32 priority);
/** /**
* @brief Adds a new main menu entry * @brief Adds a new main menu entry
@ -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
@ -698,19 +700,19 @@ namespace hex {
* @brief Adds a new welcome screen entry * @brief Adds a new welcome screen entry
* @param function The function to call to draw the entry * @param function The function to call to draw the entry
*/ */
void addWelcomeScreenEntry(const impl::DrawCallback &function); void addWelcomeScreenEntry(const impl::DrawCallback& function);
/** /**
* @brief Adds a new footer item * @brief Adds a new footer item
* @param function The function to call to draw the item * @param function The function to call to draw the item
*/ */
void addFooterItem(const impl::DrawCallback &function); void addFooterItem(const impl::DrawCallback& function);
/** /**
* @brief Adds a new toolbar item * @brief Adds a new toolbar item
* @param function The function to call to draw the item * @param function The function to call to draw the item
*/ */
void addToolbarItem(const impl::DrawCallback &function); void addToolbarItem(const impl::DrawCallback& function);
/** /**
* @brief Adds a new sidebar item * @brief Adds a new sidebar item
@ -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();
} }
/** /**
@ -749,7 +749,7 @@ namespace hex {
* @tparam T The provider type that extends hex::prv::Provider * @tparam T The provider type that extends hex::prv::Provider
* @param addToList Whether to display the provider in the Other Providers list in the welcome screen and File menu * @param addToList Whether to display the provider in the Other Providers list in the welcome screen and File menu
*/ */
template<std::derived_from<prv::Provider> T> template <std::derived_from<prv::Provider> T>
void add(bool addToList = true) { void add(bool addToList = true) {
auto typeName = T().getTypeName(); auto typeName = T().getTypeName();
@ -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();
} }
@ -784,23 +781,20 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the formatter * @param unlocalizedName The unlocalized name of the formatter
* @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();
} }
/** /**
@ -808,19 +802,17 @@ namespace hex {
* @param extensions The file extensions to handle * @param extensions The file extensions to handle
* @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)
: m_unlocalizedName(std::move(unlocalizedName)), : m_unlocalizedName(std::move(unlocalizedName)),
m_bytesPerCell(bytesPerCell), m_bytesPerCell(bytesPerCell),
m_maxCharsPerCell(maxCharsPerCell) { } m_maxCharsPerCell(maxCharsPerCell) {}
virtual ~DataVisualizer() = default; virtual ~DataVisualizer() = default;
@ -835,8 +827,9 @@ 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,
bool drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const; ImGuiInputTextFlags flags) const;
bool drawDefaultTextEditingTextBox(u64 address, std::string& data, ImGuiInputTextFlags flags) const;
private: private:
std::string m_unlocalizedName; std::string m_unlocalizedName;
@ -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();
} }
/** /**
@ -857,8 +848,8 @@ namespace hex {
* @tparam T The data visualizer type that extends hex::DataVisualizer * @tparam T The data visualizer type that extends hex::DataVisualizer
* @param args The arguments to pass to the constructor of the data visualizer * @param args The arguments to pass to the constructor of the data visualizer
*/ */
template<std::derived_from<DataVisualizer> T, typename... Args> template <std::derived_from<DataVisualizer> T, typename... Args>
void addDataVisualizer(Args &&...args) { void addDataVisualizer(Args&&... args) {
return impl::addDataVisualizer(std::make_shared<T>(std::forward<Args>(args)...)); return impl::addDataVisualizer(std::make_shared<T>(std::forward<Args>(args)...));
} }
@ -867,13 +858,11 @@ namespace hex {
* @param unlocalizedName Unlocalized name of the data visualizer * @param unlocalizedName Unlocalized name of the data visualizer
* @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,13 +873,11 @@ 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]] const Hash* getType() const { return this->m_type; }
[[nodiscard]] Hash *getType() { return this->m_type; } [[nodiscard]] const std::string& getName() const { return this->m_name; }
[[nodiscard]] const Hash *getType() const { return this->m_type; }
[[nodiscard]] const std::string &getName() const { return this->m_name; }
const std::vector<u8>& get(const Region& region, prv::Provider *provider) { const std::vector<u8>& get(const Region& region, prv::Provider *provider) {
if (this->m_cache.empty()) { if (this->m_cache.empty()) {
@ -912,19 +899,19 @@ namespace hex {
std::vector<u8> m_cache; std::vector<u8> m_cache;
}; };
virtual void draw() { } virtual void draw() {}
[[nodiscard]] virtual Function create(std::string name) = 0; [[nodiscard]] virtual Function create(std::string name) = 0;
[[nodiscard]] virtual nlohmann::json store() const = 0; [[nodiscard]] virtual nlohmann::json store() const = 0;
virtual void load(const nlohmann::json &json) = 0; virtual void load(const nlohmann::json& json) = 0;
[[nodiscard]] const std::string &getUnlocalizedName() const { [[nodiscard]] const std::string& getUnlocalizedName() const {
return this->m_unlocalizedName; return this->m_unlocalizedName;
} }
protected: protected:
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) { [[nodiscard]] Function create(const std::string& name, const Function::Callback& callback) {
return { this, name, callback }; return {this, name, callback};
} }
private: private:
@ -932,10 +919,9 @@ 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);
} }
@ -944,16 +930,14 @@ namespace hex {
* @tparam T The hash type that extends hex::Hash * @tparam T The hash type that extends hex::Hash
* @param args The arguments to pass to the constructor of the hash * @param args The arguments to pass to the constructor of the hash
*/ */
template<typename T, typename ... Args> template <typename T, typename... Args>
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()>;
@ -962,62 +946,95 @@ namespace hex {
std::jthread thread; std::jthread thread;
}; };
std::vector<Service> &getServices(); std::vector<Service>& getServices();
void stopServices(); void stopServices();
} }
void registerService(const std::string &unlocalizedName, const impl::Callback &callback); void registerService(const std::string& unlocalizedName, const impl::Callback& callback);
} }
/* 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&)>;
std::map<std::string, NetworkCallback> &getNetworkEndpoints(); std::map<std::string, NetworkCallback>& getNetworkEndpoints();
} }
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;
}; };
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,
void enableExperiement(const std::string &experimentName, bool enabled); const std::string& unlocalizedDescription = "");
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 {
Callback callback; Callback callback;
}; };
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)...));
}
} }
} }
} }

View File

@ -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));
}
}
}
} }

View File

@ -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();

View File

@ -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

View File

@ -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;
}; };
} }

View 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 &region) 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>();
}
}

View File

@ -1,450 +1,178 @@
#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 ImGui::BeginDisabled(!this->m_lines->empty());
ImGuiExt::InputHexadecimal("hex.builtin.view.disassembler.base"_lang, &this->m_baseAddress, ImGuiInputTextFlags_CharsHexadecimal); if (ImGui::BeginCombo("##architectures", Lang(this->m_currArchitecture->getUnlocalizedName()))) {
for (const auto &architecture : architectures) {
// Draw region selection picker if (ImGui::Selectable(Lang(architecture->getUnlocalizedName()))) {
ui::regionSelectionPicker(&this->m_codeRegion, provider, &this->m_range); this->m_currArchitecture = architecture.get();
// 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::SameLine();
ImGui::RadioButton("hex.builtin.view.disassembler.mips.mips3"_lang, &mode, CS_MODE_MIPS3);
static bool microMode;
ImGui::Checkbox("hex.builtin.view.disassembler.mips.micro"_lang, &microMode);
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();
}
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::EndCombo();
ImGui::BeginDisabled(this->m_disassemblerTask.isRunning()); }
ImGui::EndDisabled();
ImGui::SameLine();
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);
}
ImGuiExt::BeginSubWindow("Config");
{ {
if (ImGui::Button("hex.builtin.view.disassembler.disassemble"_lang)) this->m_currArchitecture->drawConfigInterface();
this->disassemble();
} }
ImGui::EndDisabled(); ImGuiExt::EndSubWindow();
} else {
if (ImGuiExt::DimmedButton("Reset", ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
this->m_lines->clear();
}
}
// Draw a spinner if the disassembler is running if (ImGui::BeginTable("##disassembly", 4, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable, ImGui::GetContentRegionAvail())) {
if (this->m_disassemblerTask.isRunning()) { ImGui::TableSetupScrollFreeze(0, 1);
ImGui::SameLine(); ImGui::TableSetupColumn("##jumps");
ImGuiExt::TextSpinner("hex.builtin.view.disassembler.disassembling"_lang); ImGui::TableSetupColumn("##address", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize, 80_scaled);
ImGui::TableSetupColumn("##bytes", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize, 80_scaled);
ImGui::TableSetupColumn("##instruction", ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_NoResize);
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()) {
processingStart = clipper.DisplayStart;
processingEnd = clipper.DisplayEnd;
for (auto i = processingStart; i < processingEnd; i += 1) {
auto &line = this->m_lines->at(i);
ImGui::TableNextRow();
auto height = ImGui::CalcTextSize(line.bytes.c_str(), nullptr, false, 80_scaled).y;
ImGui::TableNextColumn();
{
// 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::TableNextColumn();
if (ImGui::Selectable(hex::format("0x{:08X}", line.region.getStartAddress()).c_str(), false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(0, height))) {
ImHexApi::HexEditor::setSelection(line.region);
}
if (ImGui::IsItemHovered())
hoveredAddress = line.region.getStartAddress();
ImGui::TableNextColumn();
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_Highlight));
ImGuiExt::TextFormattedWrapped("{}", line.bytes);
ImGui::PopStyleColor();
ImGui::TableNextColumn();
ImGuiExt::TextFormattedColored(ImGui::GetColorU32(ImGuiCol_HeaderActive), "{} ", line.mnemonic);
ImGui::SameLine(0, 0);
ImGuiExt::TextFormatted("{}", line.operands);
}
} }
ImGui::NewLine(); // Draw jump arrows
{
std::list<u64> destinations;
for (auto sourceLineIndex = processingStart; sourceLineIndex < processingEnd; sourceLineIndex += 1) {
const auto &sourceLine = this->m_lines->at(sourceLineIndex);
ImGui::TextUnformatted("hex.builtin.view.disassembler.disassembly.title"_lang); if (sourceLine.jumpDestination.has_value()) {
ImGui::Separator(); for (auto destinationLineIndex = processingStart; destinationLineIndex < processingEnd; destinationLineIndex += 1) {
const auto &destinationLine = this->m_lines->at(destinationLineIndex);
// Draw disassembly table if (destinationLine.region.getStartAddress() == sourceLine.jumpDestination.value()) {
if (ImGui::BeginTable("##disassembly", 4, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) { drawJumpLine(sourceLine.linePos, destinationLine.linePos, jumpColumnWidth, destinations.size(), startCursorPos, hoveredAddress == sourceLine.region.getStartAddress() || hoveredAddress == destinationLine.region.getStartAddress());
ImGui::TableSetupScrollFreeze(0, 1); destinations.push_back(destinationLine.region.getStartAddress());
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.address"_lang); break;
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.offset"_lang);
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.bytes"_lang);
ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.title"_lang);
if (!this->m_disassemblerTask.isRunning()) {
ImGuiListClipper clipper;
clipper.Begin(this->m_disassembly.size());
ImGui::TableHeadersRow();
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
const auto &instruction = this->m_disassembly[i];
ImGui::TableNextRow();
ImGui::TableNextColumn();
// 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();
// Draw instruction address
ImGui::SameLine();
ImGuiExt::TextFormatted("0x{0:X}", instruction.address);
// Draw instruction offset
ImGui::TableNextColumn();
ImGuiExt::TextFormatted("0x{0:X}", instruction.offset);
// Draw instruction bytes
ImGui::TableNextColumn();
ImGui::TextUnformatted(instruction.bytes.c_str());
// Draw instruction mnemonic and operands
ImGui::TableNextColumn();
ImGuiExt::TextFormattedColored(ImColor(0xFFD69C56), "{}", instruction.mnemonic);
ImGui::SameLine();
ImGui::TextUnformatted(instruction.operators.c_str());
} }
} }
clipper.End(); std::erase_if(destinations, [&](u64 address) {
return sourceLine.region.getStartAddress() == address;
});
} }
ImGui::EndTable();
} }
ImGui::EndTable();
} }
} }

View File

@ -701,7 +701,7 @@ namespace hex::plugin::builtin {
auto provider = ImHexApi::Provider::get(); auto provider = ImHexApi::Provider::get();
auto reader = prv::ProviderReader (provider); auto reader = prv::ProviderReader(provider);
reader.seek(selection.getStartAddress()); reader.seek(selection.getStartAddress());
reader.setEndAddress(selection.getEndAddress()); reader.setEndAddress(selection.getEndAddress());

View File

@ -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();