summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2025-01-20 18:44:25 -0500
committerRusty Wagner <rusty.wagner@gmail.com>2025-01-20 18:44:25 -0500
commite78cae77103b5396ce42d9e33593ea55f9135be0 (patch)
treeb44cb4bf7732c1e2e77ae39335eb4e2f02d9af84
parentcbd4d7f12d54ddc4b6d3d90a8d7b49591f468a94 (diff)
Revert "Add line formatter API and a generic line formatter plugin"
This reverts commit 1699c71999d29d32aba5c9f8fea193a661a4b02b.
-rw-r--r--basicblock.cpp18
-rw-r--r--binaryninjaapi.h93
-rw-r--r--binaryninjacore.h59
-rw-r--r--formatter/generic/CMakeLists.txt45
-rw-r--r--formatter/generic/genericformatter.cpp895
-rw-r--r--formatter/generic/genericformatter.h14
-rw-r--r--lang/c/pseudoc.cpp8
-rw-r--r--lang/c/pseudoc.h3
-rw-r--r--lang/rust/pseudorust.cpp8
-rw-r--r--lang/rust/pseudorust.h3
-rw-r--r--languagerepresentation.cpp33
-rw-r--r--lineformatter.cpp225
-rw-r--r--python/__init__.py1
-rw-r--r--python/examples/pseudo_python.py13
-rw-r--r--python/function.py12
-rw-r--r--python/highlevelil.py53
-rw-r--r--python/languagerepresentation.py34
-rw-r--r--python/lineformatter.py291
18 files changed, 50 insertions, 1758 deletions
diff --git a/basicblock.cpp b/basicblock.cpp
index 2b58e30e..6bdd93ae 100644
--- a/basicblock.cpp
+++ b/basicblock.cpp
@@ -36,24 +36,6 @@ DisassemblySettings::DisassemblySettings(BNDisassemblySettings* settings)
}
-Ref<DisassemblySettings> DisassemblySettings::GetDefaultSettings()
-{
- return new DisassemblySettings(BNDefaultDisassemblySettings());
-}
-
-
-Ref<DisassemblySettings> DisassemblySettings::GetDefaultGraphSettings()
-{
- return new DisassemblySettings(BNDefaultGraphDisassemblySettings());
-}
-
-
-Ref<DisassemblySettings> DisassemblySettings::GetDefaultLinearSettings()
-{
- return new DisassemblySettings(BNDefaultLinearDisassemblySettings());
-}
-
-
DisassemblySettings* DisassemblySettings::Duplicate()
{
return new DisassemblySettings(BNDuplicateDisassemblySettings(m_object));
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 9d3c3dc8..2a2e5e9b 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -10171,10 +10171,6 @@ namespace BinaryNinja {
DisassemblySettings(BNDisassemblySettings* settings);
DisassemblySettings* Duplicate();
- static Ref<DisassemblySettings> GetDefaultSettings();
- static Ref<DisassemblySettings> GetDefaultGraphSettings();
- static Ref<DisassemblySettings> GetDefaultLinearSettings();
-
bool IsOptionSet(BNDisassemblyOption option) const;
void SetOption(BNDisassemblyOption option, bool state = true);
@@ -13698,82 +13694,6 @@ namespace BinaryNinja {
std::set<SSAVariable> GetSSAVariables();
};
- struct LineFormatterSettings
- {
- Ref<HighLevelILFunction> highLevelIL;
- size_t desiredLineLength;
- size_t minimumContentLength;
- size_t tabWidth;
- std::string languageName;
- std::string commentStartString;
- std::string commentEndString;
- std::string annotationStartString;
- std::string annotationEndString;
-
- /*! Gets the default line formatter settings for High Level IL code.
-
- \param settings The settings for reformatting.
- \param func High Level IL function to be reformatted.
- \return Settings for reformatting.
- */
- static LineFormatterSettings GetDefault(DisassemblySettings* settings, HighLevelILFunction* func);
-
- /*! Gets the default line formatter settings for a language representation function.
-
- \param settings The settings for reformatting.
- \param func Language representation function to be reformatted.
- \return Settings for reformatting.
- */
- static LineFormatterSettings GetLanguageRepresentationSettings(
- DisassemblySettings* settings, LanguageRepresentationFunction* func);
-
- static LineFormatterSettings FromAPIObject(const BNLineFormatterSettings* settings);
- BNLineFormatterSettings ToAPIObject() const;
- };
-
- class LineFormatter : public StaticCoreRefCountObject<BNLineFormatter>
- {
- std::string m_nameForRegister;
-
- static BNDisassemblyTextLine* FormatLinesCallback(void* ctxt, BNDisassemblyTextLine* inLines, size_t inCount,
- const BNLineFormatterSettings* settings, size_t* outCount);
- static void FreeLinesCallback(void* ctxt, BNDisassemblyTextLine* lines, size_t count);
-
- public:
- LineFormatter(const std::string& name);
- LineFormatter(BNLineFormatter* formatter);
-
- /*! Registers the line formatter.
-
- \param formatter The line formatter to register.
- */
- static void Register(LineFormatter* formatter);
-
- static std::vector<Ref<LineFormatter>> GetList();
- static Ref<LineFormatter> GetByName(const std::string& name);
- static Ref<LineFormatter> GetDefault();
-
- /*! Reformats the given list of lines. Returns a new list of lines containing the reformatted code.
-
- \param lines The lines to reformat.
- \param settings The settings for reformatting.
- \return A new list of reformatted lines.
- */
- virtual std::vector<DisassemblyTextLine> FormatLines(
- const std::vector<DisassemblyTextLine>& lines, const LineFormatterSettings& settings) = 0;
- };
-
- class CoreLineFormatter : public LineFormatter
- {
- public:
- CoreLineFormatter(BNLineFormatter* formatter);
-
- std::vector<DisassemblyTextLine> FormatLines(
- const std::vector<DisassemblyTextLine>& lines, const LineFormatterSettings& settings) override;
- };
-
- class LanguageRepresentationFunctionType;
-
/*! LanguageRepresentationFunction represents a single function in a registered high level language.
\ingroup highlevelil
@@ -13783,8 +13703,7 @@ namespace BinaryNinja {
BNFreeLanguageRepresentationFunction>
{
public:
- LanguageRepresentationFunction(LanguageRepresentationFunctionType* type, Architecture* arch, Function* func,
- HighLevelILFunction* highLevelIL);
+ LanguageRepresentationFunction(Architecture* arch, Function* func, HighLevelILFunction* highLevelIL);
LanguageRepresentationFunction(BNLanguageRepresentationFunction* func);
/*! Gets the lines of tokens for a given High Level IL instruction.
@@ -13823,7 +13742,6 @@ namespace BinaryNinja {
*/
BNHighlightColor GetHighlight(BasicBlock* block);
- Ref<LanguageRepresentationFunctionType> GetLanguage() const;
Ref<Architecture> GetArchitecture() const;
Ref<Function> GetFunction() const;
Ref<HighLevelILFunction> GetHighLevelILFunction() const;
@@ -13972,13 +13890,6 @@ namespace BinaryNinja {
*/
virtual Ref<TypeParser> GetTypeParser() { return nullptr; }
- /*! Returns the line formatter for formatting code in this language. If NULL is returned, the default
- formatter will be used.
-
- \return The optional formatter for formatting code in this language.
- */
- virtual Ref<LineFormatter> GetLineFormatter() { return nullptr; }
-
/*! Returns a list of lines representing a function prototype in this language. If no lines are returned, the
default C-style prototype will be used.
@@ -14005,7 +13916,6 @@ namespace BinaryNinja {
static bool IsValidCallback(void* ctxt, BNBinaryView* view);
static BNTypePrinter* GetTypePrinterCallback(void* ctxt);
static BNTypeParser* GetTypeParserCallback(void* ctxt);
- static BNLineFormatter* GetLineFormatterCallback(void* ctxt);
static BNDisassemblyTextLine* GetFunctionTypeTokensCallback(
void* ctxt, BNFunction* func, BNDisassemblySettings* settings, size_t* count);
static void FreeLinesCallback(void* ctxt, BNDisassemblyTextLine* lines, size_t count);
@@ -14020,7 +13930,6 @@ namespace BinaryNinja {
bool IsValid(BinaryView* view) override;
Ref<TypePrinter> GetTypePrinter() override;
Ref<TypeParser> GetTypeParser() override;
- Ref<LineFormatter> GetLineFormatter() override;
std::vector<DisassemblyTextLine> GetFunctionTypeTokens(
Function* func, DisassemblySettings* settings = nullptr) override;
};
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 5ac55e6b..b13a7a7a 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -37,14 +37,14 @@
// Current ABI version for linking to the core. This is incremented any time
// there are changes to the API that affect linking, including new functions,
// new types, or modifications to existing functions or types.
-#define BN_CURRENT_CORE_ABI_VERSION 89
+#define BN_CURRENT_CORE_ABI_VERSION 88
// Minimum ABI version that is supported for loading of plugins. Plugins that
// are linked to an ABI version less than this will not be able to load and
// will require rebuilding. The minimum version is increased when there are
// incompatible changes that break binary compatibility, such as changes to
// existing types or functions.
-#define BN_MINIMUM_CORE_ABI_VERSION 89
+#define BN_MINIMUM_CORE_ABI_VERSION 86
#ifdef __GNUC__
#ifdef BINARYNINJACORE_LIBRARY
@@ -302,7 +302,6 @@ extern "C"
typedef struct BNDemangler BNDemangler;
typedef struct BNFirmwareNinja BNFirmwareNinja;
typedef struct BNFirmwareNinjaReferenceNode BNFirmwareNinjaReferenceNode;
- typedef struct BNLineFormatter BNLineFormatter;
//! Console log levels
typedef enum BNLogLevel
@@ -728,7 +727,6 @@ extern "C"
HighLevelILLinearDisassembly = 65,
WaitForIL = 66,
IndentHLILBody = 67,
- DisableLineFormatting = 68,
// Debugging options
ShowFlagUsage = 128,
@@ -3441,7 +3439,6 @@ extern "C"
bool (*isValid)(void* ctxt, BNBinaryView* view);
BNTypePrinter* (*getTypePrinter)(void* ctxt);
BNTypeParser* (*getTypeParser)(void* ctxt);
- BNLineFormatter* (*getLineFormatter)(void* ctxt);
BNDisassemblyTextLine* (*getFunctionTypeTokens)(
void* ctxt, BNFunction* func, BNDisassemblySettings* settings, size_t* count);
void (*freeLines)(void* ctxt, BNDisassemblyTextLine* lines, size_t count);
@@ -3541,28 +3538,6 @@ extern "C"
size_t unique;
} BNFirmwareNinjaDeviceAccesses;
- typedef struct BNLineFormatterSettings
- {
- BNHighLevelILFunction* highLevelIL;
- size_t desiredLineLength;
- size_t minimumContentLength;
- size_t tabWidth;
- char* languageName;
- char* commentStartString;
- char* commentEndString;
- char* annotationStartString;
- char* annotationEndString;
- } BNLineFormatterSettings;
-
- typedef struct BNCustomLineFormatter
- {
- void* context;
- BNDisassemblyTextLine* (*formatLines)(void* ctxt, BNDisassemblyTextLine* inLines, size_t inCount,
- const BNLineFormatterSettings* settings, size_t* outCount);
- void (*freeLines)(void* ctxt, BNDisassemblyTextLine* lines, size_t count);
- } BNCustomLineFormatter;
-
-
BINARYNINJACOREAPI char* BNAllocString(const char* contents);
BINARYNINJACOREAPI char* BNAllocStringWithLength(const char* contents, size_t len);
BINARYNINJACOREAPI void BNFreeString(char* str);
@@ -5478,9 +5453,6 @@ extern "C"
// Disassembly settings
BINARYNINJACOREAPI BNDisassemblySettings* BNCreateDisassemblySettings(void);
- BINARYNINJACOREAPI BNDisassemblySettings* BNDefaultDisassemblySettings(void);
- BINARYNINJACOREAPI BNDisassemblySettings* BNDefaultGraphDisassemblySettings(void);
- BINARYNINJACOREAPI BNDisassemblySettings* BNDefaultLinearDisassemblySettings(void);
BINARYNINJACOREAPI BNDisassemblySettings* BNNewDisassemblySettingsReference(BNDisassemblySettings* settings);
BINARYNINJACOREAPI BNDisassemblySettings* BNDuplicateDisassemblySettings(BNDisassemblySettings* settings);
BINARYNINJACOREAPI void BNFreeDisassemblySettings(BNDisassemblySettings* settings);
@@ -6171,19 +6143,15 @@ extern "C"
BNLanguageRepresentationFunctionType* type, BNBinaryView* view);
BINARYNINJACOREAPI BNTypePrinter* BNGetLanguageRepresentationFunctionTypePrinter(BNLanguageRepresentationFunctionType* type);
BINARYNINJACOREAPI BNTypeParser* BNGetLanguageRepresentationFunctionTypeParser(BNLanguageRepresentationFunctionType* type);
- BINARYNINJACOREAPI BNLineFormatter* BNGetLanguageRepresentationFunctionTypeLineFormatter(
- BNLanguageRepresentationFunctionType* type);
BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetLanguageRepresentationFunctionTypeFunctionTypeTokens(
BNLanguageRepresentationFunctionType* type, BNFunction* func, BNDisassemblySettings* settings, size_t* count);
BINARYNINJACOREAPI BNLanguageRepresentationFunction* BNCreateCustomLanguageRepresentationFunction(
- BNLanguageRepresentationFunctionType* type, BNArchitecture* arch, BNFunction* func,
- BNHighLevelILFunction* highLevelIL, BNCustomLanguageRepresentationFunction* callbacks);
+ BNArchitecture* arch, BNFunction* func, BNHighLevelILFunction* highLevelIL,
+ BNCustomLanguageRepresentationFunction* callbacks);
BINARYNINJACOREAPI BNLanguageRepresentationFunction* BNNewLanguageRepresentationFunctionReference(
BNLanguageRepresentationFunction* func);
BINARYNINJACOREAPI void BNFreeLanguageRepresentationFunction(BNLanguageRepresentationFunction* func);
- BINARYNINJACOREAPI BNLanguageRepresentationFunctionType* BNGetLanguageRepresentationType(
- BNLanguageRepresentationFunction* func);
BINARYNINJACOREAPI BNArchitecture* BNGetLanguageRepresentationArchitecture(BNLanguageRepresentationFunction* func);
BINARYNINJACOREAPI BNFunction* BNGetLanguageRepresentationOwnerFunction(BNLanguageRepresentationFunction* func);
BINARYNINJACOREAPI BNHighLevelILFunction* BNGetLanguageRepresentationILFunction(BNLanguageRepresentationFunction* func);
@@ -8088,25 +8056,6 @@ extern "C"
BINARYNINJACOREAPI void BNFreeFirmwareNinjaReferenceNode(BNFirmwareNinjaReferenceNode* node);
BINARYNINJACOREAPI BNFirmwareNinjaReferenceNode* BNNewFirmwareNinjaReferenceNodeReference(BNFirmwareNinjaReferenceNode* node);
BINARYNINJACOREAPI void BNFreeFirmwareNinjaReferenceNodes(BNFirmwareNinjaReferenceNode** nodes, size_t count);
-
- // Line formatters
- BINARYNINJACOREAPI BNLineFormatter* BNRegisterLineFormatter(const char* name, BNCustomLineFormatter* callbacks);
- BINARYNINJACOREAPI BNLineFormatter** BNGetLineFormatterList(size_t* count);
- BINARYNINJACOREAPI void BNFreeLineFormatterList(BNLineFormatter** formatters);
- BINARYNINJACOREAPI BNLineFormatter* BNGetLineFormatterByName(const char* name);
- BINARYNINJACOREAPI BNLineFormatter* BNGetDefaultLineFormatter();
-
- BINARYNINJACOREAPI char* BNGetLineFormatterName(BNLineFormatter* formatter);
-
- BINARYNINJACOREAPI BNDisassemblyTextLine* BNFormatLines(BNLineFormatter* formatter, BNDisassemblyTextLine* inLines,
- size_t inCount, const BNLineFormatterSettings* settings, size_t* outCount);
-
- BINARYNINJACOREAPI BNLineFormatterSettings* BNGetDefaultLineFormatterSettings(
- BNDisassemblySettings* settings, BNHighLevelILFunction* func);
- BINARYNINJACOREAPI BNLineFormatterSettings* BNGetLanguageRepresentationLineFormatterSettings(
- BNDisassemblySettings* settings, BNLanguageRepresentationFunction* func);
- BINARYNINJACOREAPI void BNFreeLineFormatterSettings(BNLineFormatterSettings* settings);
-
#ifdef __cplusplus
}
#endif
diff --git a/formatter/generic/CMakeLists.txt b/formatter/generic/CMakeLists.txt
deleted file mode 100644
index 85a5a3e2..00000000
--- a/formatter/generic/CMakeLists.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
-
-project(formatter_generic)
-
-if(NOT BN_INTERNAL_BUILD)
- add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api)
-endif()
-
-file(GLOB SOURCES
- *.cpp
- *.h)
-
-if(DEMO)
- add_library(formatter_generic STATIC ${SOURCES})
-else()
- add_library(formatter_generic SHARED ${SOURCES})
-endif()
-
-target_include_directories(formatter_generic
- PRIVATE ${PROJECT_SOURCE_DIR})
-
-if(WIN32)
- target_link_directories(formatter_generic
- PRIVATE ${BN_INSTALL_DIR})
- target_link_libraries(formatter_generic binaryninjaapi binaryninjacore)
-else()
- target_link_libraries(formatter_generic binaryninjaapi)
-endif()
-
-set_target_properties(formatter_generic PROPERTIES
- CXX_STANDARD 17
- CXX_VISIBILITY_PRESET hidden
- CXX_STANDARD_REQUIRED ON
- C_STANDARD 99
- C_STANDARD_REQUIRED ON
- C_VISIBILITY_PRESET hidden
- VISIBILITY_INLINES_HIDDEN ON
- POSITION_INDEPENDENT_CODE ON)
-
-if(BN_INTERNAL_BUILD)
- plugin_rpath(formatter_generic)
- set_target_properties(formatter_generic PROPERTIES
- LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}
- RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR})
-endif()
diff --git a/formatter/generic/genericformatter.cpp b/formatter/generic/genericformatter.cpp
deleted file mode 100644
index e82f6c9b..00000000
--- a/formatter/generic/genericformatter.cpp
+++ /dev/null
@@ -1,895 +0,0 @@
-#include <ctype.h>
-#include <stack>
-#include "genericformatter.h"
-
-using namespace BinaryNinja;
-using namespace std;
-
-
-enum ItemType
-{
- Atom,
- Comment,
- Operator,
- FieldAccessor,
- Argument,
- ArgumentSeparator,
- Statement,
- StatementSeparator,
- Group,
- Container,
- StartOfContainer,
- ContainerContents,
- EndOfContainer,
-};
-
-
-static bool IsTokenWhitespace(const InstructionTextToken& token)
-{
- if (token.type == AddressDisplayToken || token.type == AddressSeparatorToken
- || token.type == CollapseStateIndicatorToken)
- return true;
-
- for (auto ch : token.text)
- {
- if (!isspace(ch))
- return false;
- }
- return true;
-}
-
-
-static string TrimString(const string& str)
-{
- size_t startPos = 0;
- size_t endPos = 0;
-
- bool start = true;
- for (size_t i = 0; i < str.size(); i++)
- {
- if (isspace(str[i]))
- {
- if (start)
- {
- startPos = i + 1;
- endPos = i + 1;
- }
- }
- else
- {
- start = false;
- endPos = i + 1;
- }
- }
-
- return str.substr(startPos, endPos - startPos);
-}
-
-
-static string TrimLeadingWhitespace(const string& str)
-{
- size_t startPos = 0;
- for (size_t i = 0; i < str.size(); i++)
- {
- if (!isspace(str[i]))
- {
- startPos = i;
- break;
- }
- }
- return str.substr(startPos);
-}
-
-
-static string TrimTrailingWhitespace(const string& str)
-{
- if (str.empty())
- return str;
-
- size_t endPos = str.size();
- for (size_t i = str.size() - 1; i > 0; i--)
- {
- if (!isspace(str[i]))
- {
- endPos = i + 1;
- break;
- }
- }
- return str.substr(0, endPos);
-}
-
-
-static const map<string, BNOperatorPrecedence> g_operatorPrecedenceMap = {{"=", AssignmentOperatorPrecedence},
- {":=", AssignmentOperatorPrecedence}, {"+=", AssignmentOperatorPrecedence}, {"-=", AssignmentOperatorPrecedence},
- {"*=", AssignmentOperatorPrecedence}, {"/=", AssignmentOperatorPrecedence}, {"s/=", AssignmentOperatorPrecedence},
- {"u/=", AssignmentOperatorPrecedence}, {"%=", AssignmentOperatorPrecedence}, {"s%=", AssignmentOperatorPrecedence},
- {"u%=", AssignmentOperatorPrecedence}, {"&=", AssignmentOperatorPrecedence}, {"|=", AssignmentOperatorPrecedence},
- {"^=", AssignmentOperatorPrecedence}, {">>=", AssignmentOperatorPrecedence}, {"s>>=", AssignmentOperatorPrecedence},
- {"u>>=", AssignmentOperatorPrecedence}, {"<<=", AssignmentOperatorPrecedence},
- {"s<<=", AssignmentOperatorPrecedence}, {"u<<=", AssignmentOperatorPrecedence}, {"?", TernaryOperatorPrecedence},
- {":", TernaryOperatorPrecedence}, {"||", LogicalOrOperatorPrecedence}, {"or", LogicalOrOperatorPrecedence},
- {"&&", LogicalAndOperatorPrecedence}, {"and", LogicalAndOperatorPrecedence}, {"&", BitwiseAndOperatorPrecedence},
- {"|", BitwiseOrOperatorPrecedence}, {"^", BitwiseXorOperatorPrecedence}, {"==", EqualityOperatorPrecedence},
- {"===", EqualityOperatorPrecedence}, {"!=", EqualityOperatorPrecedence}, {"!==", EqualityOperatorPrecedence},
- {"<>", EqualityOperatorPrecedence}, {"<", CompareOperatorPrecedence}, {"s<", CompareOperatorPrecedence},
- {"u<", CompareOperatorPrecedence}, {"<=", CompareOperatorPrecedence}, {"s<=", CompareOperatorPrecedence},
- {"u<=", CompareOperatorPrecedence}, {">", CompareOperatorPrecedence}, {"s>", CompareOperatorPrecedence},
- {"u>", CompareOperatorPrecedence}, {">=", CompareOperatorPrecedence}, {"s>=", CompareOperatorPrecedence},
- {"u>=", CompareOperatorPrecedence}, {"<<", ShiftOperatorPrecedence}, {"s<<", ShiftOperatorPrecedence},
- {"u<<", ShiftOperatorPrecedence}, {">>", ShiftOperatorPrecedence}, {"s>>", ShiftOperatorPrecedence},
- {"u>>", ShiftOperatorPrecedence}, {"+", AddOperatorPrecedence}, {"-", AddOperatorPrecedence},
- {"*", MultiplyOperatorPrecedence}, {"/", MultiplyOperatorPrecedence}, {"s/", MultiplyOperatorPrecedence},
- {"u/", MultiplyOperatorPrecedence}, {"%", MultiplyOperatorPrecedence}, {"s%", MultiplyOperatorPrecedence},
- {"u%", MultiplyOperatorPrecedence}, {"!", UnaryOperatorPrecedence}, {"not", UnaryOperatorPrecedence},
- {"~", UnaryOperatorPrecedence}};
-
-
-static BNOperatorPrecedence GetOperatorPrecedence(const InstructionTextToken& token, size_t* ternary = nullptr)
-{
- string trimmedText = TrimString(token.text);
- auto i = g_operatorPrecedenceMap.find(trimmedText);
- if (i != g_operatorPrecedenceMap.end())
- {
- if (i->second == TernaryOperatorPrecedence && ternary)
- {
- // HLIL uses ':' in additional contexts, so look for active ternary operators before
- // treating it as part of a ternary
- if (trimmedText == "?")
- {
- (*ternary)++;
- }
- else if (trimmedText == ":")
- {
- if (*ternary)
- (*ternary)--;
- else
- return MemberAndFunctionOperatorPrecedence;
- }
- }
- return i->second;
- }
- return MemberAndFunctionOperatorPrecedence;
-}
-
-
-struct Item
-{
- ItemType type;
- vector<Item> items;
- vector<InstructionTextToken> tokens;
- size_t width;
-
- void AppendAllTokens(vector<InstructionTextToken>& output, bool& firstTokenOfLine)
- {
- if (firstTokenOfLine)
- {
- if (!tokens.empty())
- {
- InstructionTextToken token = tokens.front();
- string trimmedText = TrimLeadingWhitespace(token.text);
- token.width -= token.text.size() - trimmedText.size();
- token.text = trimmedText;
- output.push_back(token);
- output.insert(output.end(), tokens.begin() + 1, tokens.end());
- firstTokenOfLine = false;
- }
- }
- else
- {
- output.insert(output.end(), tokens.begin(), tokens.end());
- }
-
- for (auto& item : items)
- item.AppendAllTokens(output, firstTokenOfLine);
- }
-
- void AddTokenToLastAtom(const InstructionTextToken& token)
- {
- if (!tokens.empty())
- tokens.push_back(token);
- else if (items.empty())
- items.push_back(Item {Atom, {}, {token}, 0});
- else
- items.back().AddTokenToLastAtom(token);
- }
-
- void CalculateWidth()
- {
- width = 0;
- for (auto& token : tokens)
- width += token.width;
- for (auto& item : items)
- {
- item.CalculateWidth();
- width += item.width;
- }
- }
-};
-
-
-struct ItemLayoutStackEntry
-{
- vector<Item> items;
- size_t additionalContinuationIndentation;
- size_t desiredWidth;
- size_t desiredContinuationWidth;
- bool newLineOnReenteringScope;
-};
-
-
-static void CalculateWidthAndIndentation(const DisassemblyTextLine& line, size_t* totalLength, size_t* indentation)
-{
- if (totalLength)
- *totalLength = 0;
- if (indentation)
- *indentation = 0;
-
- bool inIndentation = true;
- for (auto& token : line.tokens)
- {
- if (inIndentation)
- {
- if (token.type == AddressDisplayToken || token.type == AddressSeparatorToken
- || token.type == CollapseStateIndicatorToken || IsTokenWhitespace(token))
- {
- if (indentation)
- *indentation += token.width;
- }
- else
- {
- inIndentation = false;
- }
- }
-
- if (totalLength)
- *totalLength += token.width;
- }
-}
-
-
-static vector<Item> CreateStatementItems(const vector<Item>& items)
-{
- vector<Item> result, pending;
- bool hasArgs = false;
- for (auto& i : items)
- {
- if (i.type == StatementSeparator)
- {
- if (pending.empty())
- {
- result.push_back(Item {Atom, {}, {i.tokens}, 0});
- }
- else
- {
- for (auto& j : i.tokens)
- pending.back().AddTokenToLastAtom(j);
- result.push_back(Item {Statement, pending, {}, 0});
- }
- pending.clear();
- hasArgs = true;
- }
- else if (i.type == StartOfContainer && pending.empty())
- {
- result.push_back(i);
- }
- else if (i.type == EndOfContainer && hasArgs && !pending.empty())
- {
- result.push_back(Item {Statement, pending, {}, 0});
- result.push_back(i);
- pending.clear();
- }
- else
- {
- pending.push_back(Item {i.type, CreateStatementItems(i.items), i.tokens, 0});
- }
- }
-
- if (!pending.empty())
- {
- if (hasArgs)
- result.push_back(Item {Statement, pending, {}, 0});
- else
- result.insert(result.end(), pending.begin(), pending.end());
- }
-
- return result;
-}
-
-
-static vector<Item> CreateAssignmentOperatorGroups(const vector<Item>& items)
-{
- vector<Item> result, pending;
- bool hasOperators = false;
- for (auto& i : items)
- {
- if (i.type == Operator && !i.tokens.empty())
- {
- BNOperatorPrecedence precedence = GetOperatorPrecedence(i.tokens[0]);
- if (precedence == AssignmentOperatorPrecedence)
- {
- if (pending.empty())
- {
- result.push_back(Item {Atom, {}, {i.tokens}, 0});
- }
- else
- {
- for (auto& j : i.tokens)
- pending.back().AddTokenToLastAtom(j);
- result.push_back(Item {Statement, pending, {}, 0});
- }
- pending.clear();
- hasOperators = true;
- continue;
- }
- }
-
- if (i.type == StartOfContainer && pending.empty())
- {
- result.push_back(i);
- }
- else if (i.type == EndOfContainer && hasOperators && !pending.empty())
- {
- result.push_back(Item {Group, pending, {}, 0});
- result.push_back(i);
- pending.clear();
- }
- else
- {
- pending.push_back(Item {i.type, CreateAssignmentOperatorGroups(i.items), i.tokens, 0});
- }
- }
-
- if (!pending.empty())
- {
- if (hasOperators)
- result.push_back(Item {Group, pending, {}, 0});
- else
- result.insert(result.end(), pending.begin(), pending.end());
- }
-
- return result;
-}
-
-
-static vector<Item> CreateArgumentItems(const vector<Item>& items, bool inContainer)
-{
- vector<Item> result, pending;
- bool hasArgs = false;
- for (auto& i : items)
- {
- if (i.type == ArgumentSeparator)
- {
- if (pending.empty())
- {
- result.push_back(Item {Atom, {}, {i.tokens}, 0});
- }
- else
- {
- for (auto& j : i.tokens)
- pending.back().AddTokenToLastAtom(j);
- result.push_back(Item {inContainer ? Argument : Group, pending, {}, 0});
- }
- pending.clear();
- hasArgs = true;
- }
- else if (i.type == StartOfContainer && pending.empty())
- {
- result.push_back(i);
- }
- else if (i.type == EndOfContainer && hasArgs && !pending.empty())
- {
- result.push_back(Item {inContainer ? Argument : Group, pending, {}, 0});
- result.push_back(i);
- pending.clear();
- }
- else
- {
- pending.push_back(Item {i.type, CreateArgumentItems(i.items, i.type == Container), i.tokens, 0});
- }
- }
-
- if (!pending.empty())
- {
- if (hasArgs)
- result.push_back(Item {inContainer ? Argument : Group, pending, {}, 0});
- else
- result.insert(result.end(), pending.begin(), pending.end());
- }
-
- return result;
-}
-
-
-static vector<Item> CreateOperatorGroups(const vector<Item>& items)
-{
- vector<Item> result, pending;
- bool hasOperators = false;
- for (auto& i : items)
- {
- if (i.type == Operator)
- {
- if (pending.size() == 1)
- result.push_back(pending[0]);
- else if (!pending.empty())
- result.push_back(Item {Group, pending, {}, 0});
- result.push_back(i);
- pending.clear();
- hasOperators = true;
- continue;
- }
-
- if (i.type == StartOfContainer && pending.empty())
- {
- result.push_back(i);
- }
- else if (i.type == EndOfContainer && hasOperators && pending.size() > 1)
- {
- result.push_back(Item {Group, pending, {}, 0});
- result.push_back(i);
- pending.clear();
- }
- else
- {
- pending.push_back(Item {i.type, CreateOperatorGroups(i.items), i.tokens, 0});
- }
- }
-
- if (!pending.empty())
- {
- if (hasOperators && pending.size() > 1)
- result.push_back(Item {Group, pending, {}, 0});
- else
- result.insert(result.end(), pending.begin(), pending.end());
- }
-
- return result;
-}
-
-
-static vector<Item> CreateOperatorPrecedenceGroups(const vector<Item>& items)
-{
- // Look for the operator with the lowest precedence. These will be grouped first.
- optional<BNOperatorPrecedence> lowestPrecedence;
- size_t ternary = 0;
- for (auto i = items.begin(); i != items.end(); ++i)
- {
- if (i != items.begin() && i->type == Operator && !i->tokens.empty())
- {
- BNOperatorPrecedence precedence = GetOperatorPrecedence(i->tokens[0], &ternary);
- if (!lowestPrecedence.has_value() || precedence < lowestPrecedence.value())
- lowestPrecedence = precedence;
- }
- }
-
- // If there were no operators, no need to group at this level. Just traverse down into child items.
- if (!lowestPrecedence.has_value())
- {
- vector<Item> result;
- result.reserve(items.size());
- for (auto& i : items)
- result.push_back({i.type, CreateOperatorPrecedenceGroups(i.items), i.tokens, 0});
- return result;
- }
-
- // Go through the items and split the items into groups around the lowest precedence operator
- vector<Item> result, pending;
- ternary = 0;
- for (auto i = items.begin(); i != items.end(); ++i)
- {
- if (i != items.begin() && i->type == Operator && !i->tokens.empty())
- {
- BNOperatorPrecedence precedence = GetOperatorPrecedence(i->tokens[0], &ternary);
- if (precedence == lowestPrecedence.value())
- {
- if (pending.size() == 1)
- result.push_back(pending[0]);
- else if (!pending.empty())
- result.push_back(Item {Group, pending, {}, 0});
- else
- result.insert(result.end(), pending.begin(), pending.end());
- pending.clear();
- }
- }
-
- if (i->type == StartOfContainer && pending.empty())
- {
- result.push_back(*i);
- }
- else if (i->type == EndOfContainer && pending.size() > 1 && !result.empty())
- {
- result.push_back(Item {Group, pending, {}, 0});
- result.push_back(*i);
- pending.clear();
- }
- else
- {
- pending.push_back(*i);
- }
- }
-
- if (!pending.empty())
- {
- if (pending.size() > 1 && !result.empty())
- result.push_back(Item {Group, pending, {}, 0});
- else
- result.insert(result.end(), pending.begin(), pending.end());
- }
-
- // Recurse into these groups and process the next lowest precedence in each
- vector<Item> processed;
- processed.reserve(result.size());
- for (auto& i : result)
- processed.push_back({i.type, CreateOperatorPrecedenceGroups(i.items), i.tokens, 0});
- return processed;
-}
-
-
-static vector<Item> RelocateStartAndEndOfContainerItems(const vector<Item>& items)
-{
- vector<Item> result;
- for (auto& i : items)
- {
- if (!result.empty() && i.type == Container && !i.items.empty() && i.items.front().type == StartOfContainer)
- {
- Item startOfContainer = i.items.front();
- for (auto& j : startOfContainer.tokens)
- result.back().AddTokenToLastAtom(j);
-
- vector<Item> containerItems(i.items.begin() + 1, i.items.end());
- containerItems = RelocateStartAndEndOfContainerItems(containerItems);
- result.push_back({Container, containerItems, {}, 0});
- }
- else if (i.type == EndOfContainer && !result.empty())
- {
- for (auto& j : i.tokens)
- result.back().AddTokenToLastAtom(j);
- }
- else
- {
- result.push_back(Item {i.type, RelocateStartAndEndOfContainerItems(i.items), i.tokens, 0});
- }
- }
- return result;
-}
-
-
-GenericLineFormatter::GenericLineFormatter(): LineFormatter("GenericLineFormatter")
-{
-}
-
-
-vector<DisassemblyTextLine> GenericLineFormatter::FormatLines(
- const vector<DisassemblyTextLine>& lines, const LineFormatterSettings& settings)
-{
- vector<DisassemblyTextLine> result;
- for (size_t i = 0; i < lines.size(); i++)
- {
- const DisassemblyTextLine& currentLine = lines[i];
-
- size_t totalLength, indentation;
- CalculateWidthAndIndentation(currentLine, &totalLength, &indentation);
-
- // Check width against settings
- size_t contentLength = totalLength - indentation;
- if (totalLength <= settings.desiredLineLength || contentLength <= settings.minimumContentLength)
- {
- // Line fits, emit as-is
- result.push_back(currentLine);
- continue;
- }
-
- // Calculate indentation for continuation lines. If the next line in the input is more indented, make
- // the continuation lines more indented than that to separate the continuation from the new scope.
- size_t continuationIndentation = indentation + settings.tabWidth;
- if ((i + 1) < lines.size())
- {
- size_t nextLineIndentation;
- CalculateWidthAndIndentation(lines[i + 1], nullptr, &nextLineIndentation);
- if (nextLineIndentation > indentation)
- continuationIndentation = nextLineIndentation + settings.tabWidth;
- }
- size_t additionalContinuationIndentation = continuationIndentation - indentation;
-
- // Compute the target length for this line
- size_t desiredWidth = settings.minimumContentLength;
- if (indentation < settings.desiredLineLength)
- {
- size_t remainingWidth = settings.desiredLineLength - indentation;
- if (remainingWidth > desiredWidth)
- desiredWidth = remainingWidth;
- }
-
- // Compute the target length for the continuation lines
- size_t desiredContinuationWidth = settings.minimumContentLength;
- if (continuationIndentation < settings.desiredLineLength)
- {
- size_t remainingWidth = settings.desiredLineLength - continuationIndentation;
- if (remainingWidth > desiredContinuationWidth)
- desiredContinuationWidth = remainingWidth;
- }
-
- // Gather the indentation tokens at the beginning of the line
- vector<InstructionTextToken> indentationTokens;
- size_t tokenIndex = 0;
- for (tokenIndex = 0; tokenIndex < currentLine.tokens.size(); tokenIndex++)
- {
- if (IsTokenWhitespace(currentLine.tokens[tokenIndex]))
- indentationTokens.push_back(currentLine.tokens[tokenIndex]);
- else
- break;
- }
-
- // First break the line down into nested container items. A container is anything between a pair of
- // BraceTokens (except for strings, where the entire string, including the quotes, are treated as
- // a single atom).
- vector<Item> items;
- stack<vector<Item>> itemStack;
- for (; tokenIndex < currentLine.tokens.size(); tokenIndex++)
- {
- const InstructionTextToken& token = currentLine.tokens[tokenIndex];
- string trimmedText = TrimString(token.text);
-
- switch (token.type)
- {
- case BraceToken:
- if (tokenIndex + 1 < currentLine.tokens.size()
- && currentLine.tokens[tokenIndex + 1].type == StringToken)
- {
- // Treat string tokens surrounded by brace tokens as a unit (this is usually the quotes
- // surrounding the string)
- Item atom;
- atom.type = Atom;
- atom.tokens.push_back(token);
- atom.tokens.push_back(currentLine.tokens[tokenIndex + 1]);
- atom.width = 0;
- tokenIndex++;
- if (tokenIndex + 1 < currentLine.tokens.size()
- && currentLine.tokens[tokenIndex + 1].type == BraceToken)
- {
- atom.tokens.push_back(currentLine.tokens[tokenIndex + 1]);
- tokenIndex++;
- }
-
- items.push_back(atom);
- break;
- }
-
- if (trimmedText == "(" || trimmedText == "[" || trimmedText == "{")
- {
- // Create a ContainerContents item and place it onto the item stack. This will hold anything
- // inside the container once the end of the container is found.
- items.push_back(Item {Container, {}, {}, 0});
- itemStack.push(items);
-
- // Starting a new context
- items.clear();
- items.push_back(Item {StartOfContainer, {}, {token}, 0});
- }
- else if (trimmedText == ")" || trimmedText == "]" || trimmedText == "}")
- {
- items.push_back(Item {EndOfContainer, {}, {token}, 0});
-
- if (itemStack.empty())
- break;
-
- // Go back up the item stack and add the items to the container
- vector<Item> parent = itemStack.top();
- itemStack.pop();
- parent.back().items.insert(parent.back().items.end(), items.begin(), items.end());
- items = parent;
- }
- break;
- case CommentToken:
- {
- // The rest of the line is a comment. There may be tokens that are not of CommentToken type, but
- // these are used to create clickable items when things are referenced by the comment.
- Item comment {Comment, {}, {}, 0};
- for (; tokenIndex < currentLine.tokens.size(); tokenIndex++)
- comment.tokens.push_back(currentLine.tokens[tokenIndex]);
- items.push_back(comment);
- break;
- }
- case TextToken:
- if (trimmedText == ",")
- items.push_back(Item {ArgumentSeparator, {}, {token}, 0});
- else if ((!trimmedText.empty() && trimmedText[0] == '.') || trimmedText == "->")
- items.push_back(Item {FieldAccessor, {}, {token}, 0});
- else if (trimmedText == ";")
- items.push_back(Item {StatementSeparator, {}, {token}, 0});
- else if (trimmedText == ":" && !items.empty())
- items.back().AddTokenToLastAtom(token);
- else
- items.push_back(Item {Atom, {}, {token}, 0});
- break;
- case OperationToken:
- if ((!trimmedText.empty() && trimmedText[0] == '.') || trimmedText == "->")
- items.push_back(Item {FieldAccessor, {}, {token}, 0});
- else
- items.push_back(Item {Operator, {}, {token}, 0});
- break;
- default:
- items.push_back(Item {Atom, {}, {token}, 0});
- break;
- }
- }
-
- while (!itemStack.empty())
- {
- vector<Item> parent = itemStack.top();
- itemStack.pop();
- parent.back().items.insert(parent.back().items.end(), items.begin(), items.end());
- items = parent;
- }
-
- // Process the items to find semicolons, and create statement items containing the group of items making
- // up each statement.
- items = CreateStatementItems(items);
-
- // Process the items to find assignment operators, and group up the source and destination items. This needs
- // to be done before creating arguments to better handle multiple return value constructs.
- items = CreateAssignmentOperatorGroups(items);
-
- // Process the items to find commas, and create argument items containing the group of items making
- // up each argument.
- items = CreateArgumentItems(items, false);
-
- // Process the items to find operators, and create group items containing the operands
- items = CreateOperatorGroups(items);
-
- // Process the items to group operations by operator precedence
- items = CreateOperatorPrecedenceGroups(items);
-
- // Move start of container items to the last token of the previous item, and end of container items to
- // the previous atom.
- items = RelocateStartAndEndOfContainerItems(items);
-
- // Now that items are done, compute widths for layout
- for (auto& j : items)
- j.CalculateWidth();
-
- DisassemblyTextLine outputLine = currentLine;
- outputLine.tokens = indentationTokens;
- size_t currentWidth = 0;
- bool firstTokenOfLine = true;
-
- stack<ItemLayoutStackEntry> layoutStack;
- layoutStack.push({items, additionalContinuationIndentation, desiredWidth, desiredContinuationWidth, false});
-
- auto newLine = [&]() {
- if (!firstTokenOfLine)
- {
- string lastTokenText = outputLine.tokens.back().text;
- string trimmedText = TrimTrailingWhitespace(lastTokenText);
- outputLine.tokens.back().width -= lastTokenText.size() - trimmedText.size();
- outputLine.tokens.back().text = trimmedText;
- }
-
- result.push_back(outputLine);
- outputLine.tokens = indentationTokens;
-
- // Make sure any collapsible state indicators are set to padding so that the indicators don't
- // show up more than once for a single scope.
- for (auto& outToken : outputLine.tokens)
- {
- if (outToken.type == CollapseStateIndicatorToken)
- outToken.context = ContentCollapsiblePadding;
- }
-
- outputLine.tokens.emplace_back(TextToken, string(additionalContinuationIndentation, ' '));
- currentWidth = 0;
- desiredWidth = desiredContinuationWidth;
- firstTokenOfLine = true;
- };
-
- while (!layoutStack.empty())
- {
- ItemLayoutStackEntry layoutStackEntry = layoutStack.top();
- layoutStack.pop();
-
- items = layoutStackEntry.items;
- additionalContinuationIndentation = layoutStackEntry.additionalContinuationIndentation;
- desiredWidth = layoutStackEntry.desiredWidth;
- desiredContinuationWidth = layoutStackEntry.desiredContinuationWidth;
-
- // Check to see if the scope we are returning to needs a new line. This is used when an argument
- // spans multiple lines. The rest of the arguments are placed on separate lines from the long argument.
- if (layoutStackEntry.newLineOnReenteringScope && currentWidth > 0)
- newLine();
-
- for (auto item = items.begin(); item != items.end();)
- {
- if (currentWidth + item->width > desiredWidth)
- {
- // Current item is too wide to fit on the current line, will need to start a new line.
- auto next = item;
- ++next;
-
- // If we are already on a fresh line, or the item is too wide to fit on a new line of its
- // own, we have to start emitting tokens and wrap in the middle of the item. If the item
- // is a container, always use the splitting behavior.
- if (currentWidth == 0 || item->width > desiredContinuationWidth || item->type == Container)
- {
- if (item->type == Argument && currentWidth != 0)
- {
- // If an argument is too wide to show on a single line all by itself, start the argument
- // on a new line, and add additional indentation for the continuation of the argument.
- if (next != items.end())
- {
- layoutStack.push({vector(next, items.end()), additionalContinuationIndentation,
- desiredWidth, desiredContinuationWidth, true});
- }
-
- newLine();
-
- additionalContinuationIndentation += settings.tabWidth;
- if (desiredContinuationWidth < settings.minimumContentLength + settings.tabWidth)
- desiredContinuationWidth = settings.minimumContentLength;
- else
- desiredContinuationWidth -= settings.tabWidth;
-
- layoutStack.push({item->items, additionalContinuationIndentation, desiredWidth,
- desiredContinuationWidth, false});
- break;
- }
-
- if (item->tokens.empty())
- {
- // Item contains other items. Place the context onto the layout stack and resume processing.
- if (next != items.end())
- {
- layoutStack.push({vector(next, items.end()), additionalContinuationIndentation,
- desiredWidth, desiredContinuationWidth, false});
- }
- layoutStack.push({item->items, additionalContinuationIndentation, desiredWidth,
- desiredContinuationWidth, false});
- break;
- }
-
- // Item is an atom. We just have to emit the tokens even though it is too wide.
- item->AppendAllTokens(outputLine.tokens, firstTokenOfLine);
- ++item;
- continue;
- }
-
- // Start a new line and add the item on the fresh line.
- newLine();
- continue;
- }
-
- // Item fits, emit all tokens for it
- item->AppendAllTokens(outputLine.tokens, firstTokenOfLine);
- currentWidth += item->width;
- ++item;
- }
- }
-
- // Emit the last line if it had tokens
- if (currentWidth > 0)
- newLine();
- }
-
- return result;
-}
-
-
-extern "C"
-{
- BN_DECLARE_CORE_ABI_VERSION
-
-#ifndef DEMO_EDITION
- BINARYNINJAPLUGIN void CorePluginDependencies()
- {
- }
-#endif
-
-#ifdef DEMO_EDITION
- bool GenericFormatterPluginInit()
-#else
- BINARYNINJAPLUGIN bool CorePluginInit()
-#endif
- {
- GenericLineFormatter* formatter = new GenericLineFormatter();
- LineFormatter::Register(formatter);
- return true;
- }
-}
diff --git a/formatter/generic/genericformatter.h b/formatter/generic/genericformatter.h
deleted file mode 100644
index d48758ee..00000000
--- a/formatter/generic/genericformatter.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-
-#include "binaryninjaapi.h"
-
-
-class GenericLineFormatter: public BinaryNinja::LineFormatter
-{
-public:
- GenericLineFormatter();
-
- std::vector<BinaryNinja::DisassemblyTextLine> FormatLines(
- const std::vector<BinaryNinja::DisassemblyTextLine>& lines,
- const BinaryNinja::LineFormatterSettings& settings) override;
-};
diff --git a/lang/c/pseudoc.cpp b/lang/c/pseudoc.cpp
index 52622f57..dff591ff 100644
--- a/lang/c/pseudoc.cpp
+++ b/lang/c/pseudoc.cpp
@@ -6,9 +6,9 @@ using namespace std;
using namespace BinaryNinja;
-PseudoCFunction::PseudoCFunction(LanguageRepresentationFunctionType* type, Architecture* arch, Function* owner,
- HighLevelILFunction* highLevelILFunction) :
- LanguageRepresentationFunction(type, arch, owner, highLevelILFunction), m_highLevelIL(highLevelILFunction)
+PseudoCFunction::PseudoCFunction(
+ Architecture* arch, Function* owner, HighLevelILFunction* highLevelILFunction) :
+ LanguageRepresentationFunction(arch, owner, highLevelILFunction), m_highLevelIL(highLevelILFunction)
{
}
@@ -2766,7 +2766,7 @@ PseudoCFunctionType::PseudoCFunctionType(): LanguageRepresentationFunctionType("
Ref<LanguageRepresentationFunction> PseudoCFunctionType::Create(Architecture* arch, Function* owner,
HighLevelILFunction* highLevelILFunction)
{
- return new PseudoCFunction(this, arch, owner, highLevelILFunction);
+ return new PseudoCFunction(arch, owner, highLevelILFunction);
}
diff --git a/lang/c/pseudoc.h b/lang/c/pseudoc.h
index feb64552..024be2f1 100644
--- a/lang/c/pseudoc.h
+++ b/lang/c/pseudoc.h
@@ -51,8 +51,7 @@ protected:
const BinaryNinja::HighLevelILInstruction& instr, BinaryNinja::HighLevelILTokenEmitter& tokens) override;
public:
- PseudoCFunction(BinaryNinja::LanguageRepresentationFunctionType* type, BinaryNinja::Architecture* arch,
- BinaryNinja::Function* owner, BinaryNinja::HighLevelILFunction* highLevelILFunction);
+ PseudoCFunction(BinaryNinja::Architecture* arch, BinaryNinja::Function* owner, BinaryNinja::HighLevelILFunction* highLevelILFunction);
std::string GetAnnotationStartString() const override;
std::string GetAnnotationEndString() const override;
diff --git a/lang/rust/pseudorust.cpp b/lang/rust/pseudorust.cpp
index a1f7defe..837a7932 100644
--- a/lang/rust/pseudorust.cpp
+++ b/lang/rust/pseudorust.cpp
@@ -7,9 +7,9 @@ using namespace std;
using namespace BinaryNinja;
-PseudoRustFunction::PseudoRustFunction(LanguageRepresentationFunctionType* type, Architecture* arch, Function* owner,
- HighLevelILFunction* highLevelILFunction) :
- LanguageRepresentationFunction(type, arch, owner, highLevelILFunction), m_highLevelIL(highLevelILFunction)
+PseudoRustFunction::PseudoRustFunction(
+ Architecture* arch, Function* owner, HighLevelILFunction* highLevelILFunction) :
+ LanguageRepresentationFunction(arch, owner, highLevelILFunction), m_highLevelIL(highLevelILFunction)
{
}
@@ -2814,7 +2814,7 @@ PseudoRustFunctionType::PseudoRustFunctionType(): LanguageRepresentationFunction
Ref<LanguageRepresentationFunction> PseudoRustFunctionType::Create(Architecture* arch, Function* owner,
HighLevelILFunction* highLevelILFunction)
{
- return new PseudoRustFunction(this, arch, owner, highLevelILFunction);
+ return new PseudoRustFunction(arch, owner, highLevelILFunction);
}
diff --git a/lang/rust/pseudorust.h b/lang/rust/pseudorust.h
index 96e656c2..a2ab9584 100644
--- a/lang/rust/pseudorust.h
+++ b/lang/rust/pseudorust.h
@@ -59,8 +59,7 @@ protected:
virtual void EndLines(const BinaryNinja::HighLevelILInstruction& instr, BinaryNinja::HighLevelILTokenEmitter& tokens) override;
public:
- PseudoRustFunction(BinaryNinja::LanguageRepresentationFunctionType* type, BinaryNinja::Architecture* arch,
- BinaryNinja::Function* owner, BinaryNinja::HighLevelILFunction* highLevelILFunction);
+ PseudoRustFunction(BinaryNinja::Architecture* arch, BinaryNinja::Function* owner, BinaryNinja::HighLevelILFunction* highLevelILFunction);
std::string GetAnnotationStartString() const override;
std::string GetAnnotationEndString() const override;
diff --git a/languagerepresentation.cpp b/languagerepresentation.cpp
index 1af38b4b..0930c0b8 100644
--- a/languagerepresentation.cpp
+++ b/languagerepresentation.cpp
@@ -4,8 +4,7 @@
using namespace BinaryNinja;
using namespace std;
-LanguageRepresentationFunction::LanguageRepresentationFunction(
- LanguageRepresentationFunctionType* type, Architecture* arch, Function* func, HighLevelILFunction* highLevelIL)
+LanguageRepresentationFunction::LanguageRepresentationFunction(Architecture* arch, Function* func, HighLevelILFunction* highLevelIL)
{
BNCustomLanguageRepresentationFunction callbacks;
callbacks.context = this;
@@ -21,8 +20,8 @@ LanguageRepresentationFunction::LanguageRepresentationFunction(
callbacks.getAnnotationStartString = GetAnnotationStartStringCallback;
callbacks.getAnnotationEndString = GetAnnotationEndStringCallback;
AddRefForRegistration();
- m_object = BNCreateCustomLanguageRepresentationFunction(
- type->GetObject(), arch->GetObject(), func->GetObject(), highLevelIL->GetObject(), &callbacks);
+ m_object = BNCreateCustomLanguageRepresentationFunction(arch->GetObject(), func->GetObject(),
+ highLevelIL->GetObject(), &callbacks);
}
@@ -113,12 +112,6 @@ BNHighlightColor LanguageRepresentationFunction::GetHighlight(BasicBlock* block)
}
-Ref<LanguageRepresentationFunctionType> LanguageRepresentationFunction::GetLanguage() const
-{
- return new CoreLanguageRepresentationFunctionType(BNGetLanguageRepresentationType(m_object));
-}
-
-
Ref<Architecture> LanguageRepresentationFunction::GetArchitecture() const
{
return new CoreArchitecture(BNGetLanguageRepresentationArchitecture(m_object));
@@ -319,7 +312,6 @@ void LanguageRepresentationFunctionType::Register(LanguageRepresentationFunction
callbacks.isValid = IsValidCallback;
callbacks.getTypePrinter = GetTypePrinterCallback;
callbacks.getTypeParser = GetTypeParserCallback;
- callbacks.getLineFormatter = GetLineFormatterCallback;
callbacks.getFunctionTypeTokens = GetFunctionTypeTokensCallback;
callbacks.freeLines = FreeLinesCallback;
@@ -371,16 +363,6 @@ BNTypeParser* LanguageRepresentationFunctionType::GetTypeParserCallback(void* ct
}
-BNLineFormatter* LanguageRepresentationFunctionType::GetLineFormatterCallback(void* ctxt)
-{
- LanguageRepresentationFunctionType* type = (LanguageRepresentationFunctionType*)ctxt;
- Ref<LineFormatter> result = type->GetLineFormatter();
- if (!result)
- return nullptr;
- return result->GetObject();
-}
-
-
BNDisassemblyTextLine* LanguageRepresentationFunctionType::GetFunctionTypeTokensCallback(
void* ctxt, BNFunction* func, BNDisassemblySettings* settings, size_t* count)
{
@@ -490,15 +472,6 @@ Ref<TypeParser> CoreLanguageRepresentationFunctionType::GetTypeParser()
}
-Ref<LineFormatter> CoreLanguageRepresentationFunctionType::GetLineFormatter()
-{
- BNLineFormatter* formatter = BNGetLanguageRepresentationFunctionTypeLineFormatter(m_object);
- if (!formatter)
- return nullptr;
- return new CoreLineFormatter(formatter);
-}
-
-
vector<DisassemblyTextLine> CoreLanguageRepresentationFunctionType::GetFunctionTypeTokens(
Function* func, DisassemblySettings* settings)
{
diff --git a/lineformatter.cpp b/lineformatter.cpp
deleted file mode 100644
index 71da6b6e..00000000
--- a/lineformatter.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright (c) 2024 Vector 35 Inc
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-// IN THE SOFTWARE.
-
-#include "binaryninjaapi.h"
-
-using namespace BinaryNinja;
-using namespace std;
-
-
-LineFormatterSettings LineFormatterSettings::GetDefault(DisassemblySettings* settings, HighLevelILFunction* func)
-{
- BNLineFormatterSettings* apiObj =
- BNGetDefaultLineFormatterSettings(settings ? settings->GetObject() : nullptr, func->GetObject());
- LineFormatterSettings result = FromAPIObject(apiObj);
- BNFreeLineFormatterSettings(apiObj);
- return result;
-}
-
-
-LineFormatterSettings LineFormatterSettings::GetLanguageRepresentationSettings(
- DisassemblySettings* settings, LanguageRepresentationFunction* func)
-{
- BNLineFormatterSettings* apiObj =
- BNGetLanguageRepresentationLineFormatterSettings(settings ? settings->GetObject() : nullptr, func->GetObject());
- LineFormatterSettings result = FromAPIObject(apiObj);
- BNFreeLineFormatterSettings(apiObj);
- return result;
-}
-
-
-LineFormatterSettings LineFormatterSettings::FromAPIObject(const BNLineFormatterSettings* settings)
-{
- LineFormatterSettings result;
- result.highLevelIL = new HighLevelILFunction(BNNewHighLevelILFunctionReference(settings->highLevelIL));
- result.desiredLineLength = settings->desiredLineLength;
- result.minimumContentLength = settings->minimumContentLength;
- result.tabWidth = settings->tabWidth;
- result.languageName = settings->languageName;
- result.commentStartString = settings->commentStartString;
- result.commentEndString = settings->commentEndString;
- result.annotationStartString = settings->annotationStartString;
- result.annotationEndString = settings->annotationEndString;
- return result;
-}
-
-
-BNLineFormatterSettings LineFormatterSettings::ToAPIObject() const
-{
- BNLineFormatterSettings result;
- result.highLevelIL = highLevelIL->GetObject();
- result.desiredLineLength = desiredLineLength;
- result.minimumContentLength = minimumContentLength;
- result.tabWidth = tabWidth;
- result.languageName = (char*)languageName.c_str();
- result.commentStartString = (char*)commentStartString.c_str();
- result.commentEndString = (char*)commentEndString.c_str();
- result.annotationStartString = (char*)annotationStartString.c_str();
- result.annotationEndString = (char*)annotationEndString.c_str();
- return result;
-}
-
-
-LineFormatter::LineFormatter(const string& name) : m_nameForRegister(name) {}
-
-
-LineFormatter::LineFormatter(BNLineFormatter* formatter)
-{
- m_object = formatter;
-}
-
-
-void LineFormatter::Register(LineFormatter* formatter)
-{
- BNCustomLineFormatter cb;
- cb.context = formatter;
- cb.formatLines = FormatLinesCallback;
- cb.freeLines = FreeLinesCallback;
-
- formatter->AddRefForRegistration();
- formatter->m_object = BNRegisterLineFormatter(formatter->m_nameForRegister.c_str(), &cb);
-}
-
-
-BNDisassemblyTextLine* LineFormatter::FormatLinesCallback(void* ctxt, BNDisassemblyTextLine* inLines, size_t inCount,
- const BNLineFormatterSettings* settings, size_t* outCount)
-{
- LineFormatter* formatter = (LineFormatter*)ctxt;
-
- vector<DisassemblyTextLine> input;
- input.reserve(inCount);
- for (size_t i = 0; i < inCount; i++)
- {
- DisassemblyTextLine line;
- line.addr = inLines[i].addr;
- line.instrIndex = inLines[i].instrIndex;
- line.highlight = inLines[i].highlight;
- line.tokens = InstructionTextToken::ConvertInstructionTextTokenList(inLines[i].tokens, inLines[i].count);
- line.tags = Tag::ConvertTagList(inLines[i].tags, inLines[i].tagCount);
- input.push_back(line);
- }
-
- vector<DisassemblyTextLine> outLines =
- formatter->FormatLines(input, LineFormatterSettings::FromAPIObject(settings));
-
- *outCount = outLines.size();
- BNDisassemblyTextLine* buf = new BNDisassemblyTextLine[outLines.size()];
- for (size_t i = 0; i < outLines.size(); i++)
- {
- const DisassemblyTextLine& line = outLines[i];
- buf[i].addr = line.addr;
- buf[i].instrIndex = line.instrIndex;
- buf[i].highlight = line.highlight;
- buf[i].tokens = InstructionTextToken::CreateInstructionTextTokenList(line.tokens);
- buf[i].count = line.tokens.size();
- buf[i].tags = Tag::CreateTagList(line.tags, &(buf[i].tagCount));
- }
-
- return buf;
-}
-
-
-void LineFormatter::FreeLinesCallback(void*, BNDisassemblyTextLine* lines, size_t count)
-{
- for (size_t i = 0; i < count; i++)
- {
- InstructionTextToken::FreeInstructionTextTokenList(lines[i].tokens, lines[i].count);
- Tag::FreeTagList(lines[i].tags, lines[i].tagCount);
- }
- delete[] lines;
-}
-
-
-vector<Ref<LineFormatter>> LineFormatter::GetList()
-{
- size_t count;
- BNLineFormatter** list = BNGetLineFormatterList(&count);
- vector<Ref<LineFormatter>> result;
- for (size_t i = 0; i < count; i++)
- result.push_back(new CoreLineFormatter(list[i]));
- BNFreeLineFormatterList(list);
- return result;
-}
-
-
-Ref<LineFormatter> LineFormatter::GetByName(const string& name)
-{
- BNLineFormatter* result = BNGetLineFormatterByName(name.c_str());
- if (!result)
- return nullptr;
- return new CoreLineFormatter(result);
-}
-
-
-Ref<LineFormatter> LineFormatter::GetDefault()
-{
- BNLineFormatter* result = BNGetDefaultLineFormatter();
- if (!result)
- return nullptr;
- return new CoreLineFormatter(result);
-}
-
-
-CoreLineFormatter::CoreLineFormatter(BNLineFormatter* formatter) : LineFormatter(formatter) {}
-
-
-vector<DisassemblyTextLine> CoreLineFormatter::FormatLines(
- const vector<DisassemblyTextLine>& lines, const LineFormatterSettings& settings)
-{
- size_t inCount = lines.size();
- BNDisassemblyTextLine* inLines = new BNDisassemblyTextLine[lines.size()];
- for (size_t i = 0; i < lines.size(); i++)
- {
- const DisassemblyTextLine& line = lines[i];
- inLines[i].addr = line.addr;
- inLines[i].instrIndex = line.instrIndex;
- inLines[i].highlight = line.highlight;
- inLines[i].tokens = InstructionTextToken::CreateInstructionTextTokenList(line.tokens);
- inLines[i].count = line.tokens.size();
- inLines[i].tags = Tag::CreateTagList(line.tags, &(inLines[i].tagCount));
- }
-
- size_t outCount = 0;
- BNLineFormatterSettings apiSettings = settings.ToAPIObject();
- BNDisassemblyTextLine* outLines = BNFormatLines(m_object, inLines, inCount, &apiSettings, &outCount);
-
- for (size_t i = 0; i < inCount; i++)
- {
- InstructionTextToken::FreeInstructionTextTokenList(inLines[i].tokens, inLines[i].count);
- Tag::FreeTagList(inLines[i].tags, inLines[i].tagCount);
- }
- delete[] inLines;
-
- vector<DisassemblyTextLine> result;
- result.reserve(outCount);
- for (size_t i = 0; i < outCount; i++)
- {
- DisassemblyTextLine line;
- line.addr = outLines[i].addr;
- line.instrIndex = outLines[i].instrIndex;
- line.highlight = outLines[i].highlight;
- line.tokens = InstructionTextToken::ConvertInstructionTextTokenList(outLines[i].tokens, outLines[i].count);
- line.tags = Tag::ConvertTagList(outLines[i].tags, outLines[i].tagCount);
- result.push_back(line);
- }
-
- BNFreeDisassemblyTextLines(outLines, outCount);
- return result;
-}
diff --git a/python/__init__.py b/python/__init__.py
index 1cdc541e..9b5a394e 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -80,7 +80,6 @@ from .externallibrary import *
from .undo import *
from .fileaccessor import *
from .languagerepresentation import *
-from .lineformatter import *
# We import each of these by name to prevent conflicts between
# log.py and the function 'log' which we don't import below
from .log import (
diff --git a/python/examples/pseudo_python.py b/python/examples/pseudo_python.py
index 655039fe..6a9e401b 100644
--- a/python/examples/pseudo_python.py
+++ b/python/examples/pseudo_python.py
@@ -316,7 +316,16 @@ class PseudoPythonFunction(LanguageRepresentationFunction):
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ": "))
tokens.append(instr.var.type.get_tokens())
elif instr.operation == HighLevelILOperation.HLIL_FLOAT_CONST:
- tokens.append(InstructionTextToken(InstructionTextTokenType.FloatingPointToken, f"{instr.constant:g}"))
+ # The constant value in the instruction contains the raw bits of the floating point value. Convert
+ # this to a floating point value and display it.
+ if instr.size == 4:
+ value = struct.unpack("<f", struct.pack("<I", instr.constant))[0]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.FloatToken, f"{value:g}"))
+ elif instr.size == 8:
+ value = struct.unpack("<d", struct.pack("<Q", instr.constant))[0]
+ tokens.append(InstructionTextToken(InstructionTextTokenType.FloatToken, f"{value:g}"))
+ else:
+ tokens.append_integer_text_token(instr, instr.constant, instr.size)
elif instr.operation == HighLevelILOperation.HLIL_CONST:
# Check for bool type. Display these as True or False. The default handling will use C style
# booleans instead of Python style.
@@ -1066,7 +1075,7 @@ class PseudoPythonFunctionType(LanguageRepresentationFunctionType):
language_name = "Pseudo Python"
def create(self, arch: Architecture, owner: Function, hlil: HighLevelILFunction):
- return PseudoPythonFunction(self, arch, owner, hlil)
+ return PseudoPythonFunction(arch, owner, hlil)
def function_type_tokens(self, func: Function, settings: DisassemblySettings) -> DisassemblyTextLine:
tokens = []
diff --git a/python/function.py b/python/function.py
index 0fc60ffc..e962d91f 100644
--- a/python/function.py
+++ b/python/function.py
@@ -135,18 +135,6 @@ class DisassemblySettings:
option = DisassemblyOption[option]
core.BNSetDisassemblySettingsOption(self.handle, option, state)
- @staticmethod
- def default_settings() -> 'DisassemblySettings':
- return DisassemblySettings(core.BNDefaultDisassemblySettings())
-
- @staticmethod
- def default_graph_settings() -> 'DisassemblySettings':
- return DisassemblySettings(core.BNDefaultGraphDisassemblySettings())
-
- @staticmethod
- def default_linear_settings() -> 'DisassemblySettings':
- return DisassemblySettings(core.BNDefaultLinearDisassemblySettings())
-
@dataclass
class ILReferenceSource:
diff --git a/python/highlevelil.py b/python/highlevelil.py
index 85be4794..1d7feb71 100644
--- a/python/highlevelil.py
+++ b/python/highlevelil.py
@@ -26,10 +26,7 @@ from enum import Enum
# Binary Ninja components
from . import _binaryninjacore as core
-from .enums import (
- HighLevelILOperation, DataFlowQueryOption, FunctionGraphType, ILInstructionAttribute, StringType,
- DisassemblyOption
-)
+from .enums import HighLevelILOperation, DataFlowQueryOption, FunctionGraphType, ILInstructionAttribute, StringType
from . import function
from . import binaryview
from . import architecture
@@ -334,9 +331,7 @@ class HighLevelILInstruction(BaseILInstruction):
return ILInstruction[instr.operation](func, expr_index, core_instr, as_ast, instr_index)
def __str__(self):
- settings = function.DisassemblySettings.default_settings()
- settings.set_option(DisassemblyOption.DisableLineFormatting)
- lines = self.get_lines(settings)
+ lines = self.lines
if lines is None:
return "invalid"
result = []
@@ -348,9 +343,7 @@ class HighLevelILInstruction(BaseILInstruction):
return '\n'.join(result)
def __repr__(self):
- settings = function.DisassemblySettings.default_settings()
- settings.set_option(DisassemblyOption.DisableLineFormatting)
- lines = self.get_lines(settings)
+ lines = self.lines
continuation = ""
if lines is None:
first_line = "<invalid>"
@@ -393,14 +386,26 @@ class HighLevelILInstruction(BaseILInstruction):
@property
def tokens(self) -> TokenList:
"""HLIL tokens taken from the HLIL text lines (read-only) -- does not include newlines or indentation, use lines for that information"""
- settings = function.DisassemblySettings.default_settings()
- settings.set_option(DisassemblyOption.DisableLineFormatting)
- return [token for line in self.get_lines(settings) for token in line.tokens]
+ return [token for line in self.lines for token in line.tokens]
@property
def lines(self) -> LinesType:
"""HLIL text lines (read-only)"""
- return self.get_lines()
+ count = ctypes.c_ulonglong()
+ lines = core.BNGetHighLevelILExprText(self.function.handle, self.expr_index, self.as_ast, count, None)
+ assert lines is not None, "core.BNGetHighLevelILExprText returned None"
+ try:
+ for i in range(0, count.value):
+ addr = lines[i].addr
+ if lines[i].instrIndex != 0xffffffffffffffff:
+ il_instr = self.function[lines[i].instrIndex]
+ else:
+ il_instr = None
+ color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
+ tokens = function.InstructionTextToken._from_core_struct(lines[i].tokens, lines[i].count)
+ yield function.DisassemblyTextLine(tokens, addr, il_instr, color)
+ finally:
+ core.BNFreeDisassemblyTextLines(lines, count.value)
@property
def prefix_operands(self) -> List[Union[HighLevelILOperandType, HighLevelILOperationAndSize]]:
@@ -913,26 +918,6 @@ class HighLevelILInstruction(BaseILInstruction):
def has_side_effects(self) -> bool:
return core.BNHighLevelILHasSideEffects(self.function.handle, self.expr_index)
- def get_lines(self, settings: Optional['function.DisassemblySettings'] = None) -> LinesType:
- """Gets HLIL text lines with optional settings"""
- if settings is not None:
- settings = settings.handle
- count = ctypes.c_ulonglong()
- lines = core.BNGetHighLevelILExprText(self.function.handle, self.expr_index, self.as_ast, count, settings)
- assert lines is not None, "core.BNGetHighLevelILExprText returned None"
- try:
- for i in range(0, count.value):
- addr = lines[i].addr
- if lines[i].instrIndex != 0xffffffffffffffff:
- il_instr = self.function[lines[i].instrIndex]
- else:
- il_instr = None
- color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
- tokens = function.InstructionTextToken._from_core_struct(lines[i].tokens, lines[i].count)
- yield function.DisassemblyTextLine(tokens, addr, il_instr, color)
- finally:
- core.BNFreeDisassemblyTextLines(lines, count.value)
-
@dataclass(frozen=True, repr=False, eq=False)
class HighLevelILUnaryBase(HighLevelILInstruction, UnaryOperation):
diff --git a/python/languagerepresentation.py b/python/languagerepresentation.py
index a0a5a234..ac34c860 100644
--- a/python/languagerepresentation.py
+++ b/python/languagerepresentation.py
@@ -30,7 +30,6 @@ from . import binaryview
from . import function
from . import highlevelil
from . import highlight
-from . import lineformatter
from . import variable
from . import types
from .log import log_error
@@ -328,8 +327,7 @@ class LanguageRepresentationFunction:
annotation_end_string = "}"
def __init__(
- self, func_type: Optional['LanguageRepresentationFunctionType'] = None,
- arch: Optional['architecture.Architecture'] = None, owner: Optional['function.Function'] = None,
+ self, arch: Optional['architecture.Architecture'] = None, owner: Optional['function.Function'] = None,
hlil: Optional['highlevelil.HighLevelILFunction'] = None, handle=None
):
if handle is None:
@@ -356,9 +354,7 @@ class LanguageRepresentationFunction:
self.comment_end_string = self.__class__.comment_end_string
self.annotation_start_string = self.__class__.annotation_start_string
self.annotation_end_string = self.__class__.annotation_end_string
- _handle = core.BNCreateCustomLanguageRepresentationFunction(
- func_type.handle, arch.handle, owner.handle, hlil.handle, self._cb
- )
+ _handle = core.BNCreateCustomLanguageRepresentationFunction(arch.handle, owner.handle, hlil.handle, self._cb)
assert _handle is not None
else:
self.comment_start_string = core.BNGetLanguageRepresentationFunctionCommentStartString(handle)
@@ -625,7 +621,6 @@ class LanguageRepresentationFunctionType(metaclass=_LanguageRepresentationFuncti
self._cb.isValid = self._cb.isValid.__class__(self._is_valid)
self._cb.getTypePrinter = self._cb.getTypePrinter.__class__(self._type_printer)
self._cb.getTypeParser = self._cb.getTypeParser.__class__(self._type_parser)
- self._cb.getLineFormatter = self._cb.getLineFormatter.__class__(self._line_formatter)
self._cb.getFunctionTypeTokens = self._cb.getFunctionTypeTokens.__class__(self._function_type_tokens)
self._cb.freeLines = self._cb.freeLines.__class__(self._free_lines)
self.handle = core.BNRegisterLanguageRepresentationFunctionType(self.__class__.language_name, self._cb)
@@ -677,16 +672,6 @@ class LanguageRepresentationFunctionType(metaclass=_LanguageRepresentationFuncti
log_error(traceback.format_exc())
return None
- def _line_formatter(self, ctxt):
- try:
- result = self.line_formatter
- if result is None:
- return None
- return ctypes.cast(result.handle, ctypes.c_void_p).value
- except:
- log_error(traceback.format_exc())
- return None
-
def _function_type_tokens(
self, ctxt, func: core.BNFunctionHandle, settings: Optional[core.BNDisassemblySettingsHandle],
count: ctypes.POINTER(ctypes.c_ulonglong)
@@ -766,14 +751,6 @@ class LanguageRepresentationFunctionType(metaclass=_LanguageRepresentationFuncti
"""
return None
- @property
- def line_formatter(self) -> Optional['lineformatter.LineFormatter']:
- """
- Returns the line formatter for formatting lines in this language. If ``None`` is returned, the default
- line formatter will be used.
- """
- return None
-
def function_type_tokens(
self, func: 'function.Function', settings: Optional['function.DisassemblySettings']
) -> List['function.DisassemblyTextLine']:
@@ -829,13 +806,6 @@ class CoreLanguageRepresentationFunctionType(LanguageRepresentationFunctionType)
return None
return binaryninja.typeparser.TypeParser(handle=result)
- @property
- def line_formatter(self) -> Optional['lineformatter.LineFormatter']:
- result = core.BNGetLanguageRepresentationFunctionTypeLineFormatter(self.handle)
- if result is None:
- return None
- return binaryninja.lineformatter.LineFormatter(handle=result)
-
def function_type_tokens(
self, func: 'function.Function', settings: Optional['function.DisassemblySettings']
) -> List['function.DisassemblyTextLine']:
diff --git a/python/lineformatter.py b/python/lineformatter.py
deleted file mode 100644
index 7f74572b..00000000
--- a/python/lineformatter.py
+++ /dev/null
@@ -1,291 +0,0 @@
-# Copyright (c) 2025 Vector 35 Inc
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to
-# deal in the Software without restriction, including without limitation the
-# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-# sell copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-import ctypes
-import traceback
-from dataclasses import dataclass
-from typing import List, Optional, Union
-
-# Binary Ninja components
-import binaryninja
-from . import _binaryninjacore as core
-from . import function
-from . import highlevelil
-from . import highlight
-from . import languagerepresentation
-from .log import log_error
-from .enums import HighlightStandardColor
-
-
-@dataclass(frozen=True)
-class LineFormatterSettings:
- hlil: highlevelil.HighLevelILFunction
- desired_line_length: int
- minimum_content_length: int
- tab_width: int
- language_name: Optional[str]
- comment_start_string: str
- comment_end_string: str
- annotation_start_string: str
- annotation_end_string: str
-
- @staticmethod
- def default(settings: Optional['function.DisassemblySettings'], hlil: 'highlevelil.HighLevelILFunction') -> 'LineFormatterSettings':
- """
- Gets the default line formatter settings for High Level IL code.
- """
- if settings is not None:
- settings = settings.handle
- api_obj = core.BNGetDefaultLineFormatterSettings(settings, hlil.handle)
- result = LineFormatterSettings._from_core_struct(api_obj[0])
- core.BNFreeLineFormatterSettings(api_obj)
- return result
-
- @staticmethod
- def language_representation_settings(
- settings: Optional['function.DisassemblySettings'], func: 'languagerepresentation.LanguageRepresentationFunction'
- ) -> 'LineFormatterSettings':
- """
- Gets the default line formatter settings for a language representation function.
- """
- if settings is not None:
- settings = settings.handle
- api_obj = core.BNGetLanguageRepresentationLineFormatterSettings(settings, func.handle)
- result = LineFormatterSettings._from_core_struct(api_obj[0])
- core.BNFreeLineFormatterSettings(api_obj)
- return result
-
- @staticmethod
- def _from_core_struct(settings: core.BNLineFormatterSettings) -> 'LineFormatterSettings':
- if len(settings.languageName) == 0:
- language_name = None
- else:
- language_name = settings.languageName
- hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(settings.highLevelIL))
- return LineFormatterSettings(
- hlil, settings.desiredLineLength, settings.minimumContentLength, settings.tabWidth, language_name,
- settings.commentStartString, settings.commentEndString,
- settings.annotationStartString, settings.annotationEndString
- )
-
- def _to_core_struct(self) -> core.BNLineFormatterSettings:
- result = core.BNLineFormatterSettings()
- result.highLevelIL = self.hlil.handle
- result.desiredLineLength = self.desired_line_length
- result.minimumContentLength = self.minimum_content_length
- result.tabWidth = self.tab_width
- result.languageName = self.language_name if self.language_name is not None else ""
- result.commentStartString = self.comment_start_string
- result.commentEndString = self.comment_end_string
- result.annotationStartString = self.annotation_start_string
- result.annotationEndString = self.annotation_end_string
- return result
-
-
-class _LineFormatterMetaClass(type):
- def __iter__(self):
- binaryninja._init_plugins()
- count = ctypes.c_ulonglong()
- types = core.BNGetLineFormatterList(count)
- assert types is not None, "core.BNGetLineFormatterList returned None"
- try:
- for i in range(0, count.value):
- yield CoreLineFormatter(handle=types[i])
- finally:
- core.BNFreeLineFormatterList(types)
-
- def __getitem__(cls, value):
- binaryninja._init_plugins()
- lang = core.BNGetLineFormatterByName(str(value))
- if lang is None:
- raise KeyError("'%s' is not a valid formatter" % str(value))
- return CoreLineFormatter(handle=lang)
-
-
-class LineFormatter(metaclass=_LineFormatterMetaClass):
- """
- ``class LineFormatter`` represents a custom line formatter, which can reformat code in High Level IL
- and high level language representations.
- """
- _registered_formatters = []
- formatter_name = None
-
- def __init__(self, handle=None):
- if handle is not None:
- self.handle = core.handle_of_type(handle, core.BNLineFormatter)
-
- def register(self):
- """Registers the line formatter."""
- if self.__class__.formatter_name is None:
- raise ValueError("formatter_name is missing")
- self._cb = core.BNCustomLineFormatter()
- self._cb.context = 0
- self._cb.formatLines = self._cb.formatLines.__class__(self._format_lines)
- self._cb.freeLines = self._cb.freeLines.__class__(self._free_lines)
- self.handle = core.BNRegisterLineFormatter(self.__class__.formatter_name, self._cb)
- self.__class__._registered_formatters.append(self)
-
- def _format_lines(
- self, ctxt, in_lines, in_count: int, settings: core.BNLineFormatterSettingsHandle,
- out_count: ctypes.POINTER(ctypes.c_ulonglong)
- ):
- try:
- settings = settings[0]
- if len(settings.languageName) == 0:
- language_name = None
- else:
- language_name = settings.languageName
- hlil = highlevelil.HighLevelILFunction(handle=core.BNNewHighLevelILFunctionReference(settings.highLevelIL))
- settings = LineFormatterSettings(
- hlil, settings.desiredLineLength, settings.minimumContentLength, settings.tabWidth, language_name,
- settings.commentStartString, settings.commentEndString,
- settings.annotationStartString, settings.annotationEndString
- )
-
- lines = []
- if in_lines is not None:
- for i in range(0, in_count):
- addr = in_lines[i].addr
- if in_lines[i].instrIndex != 0xffffffffffffffff:
- il_instr = hlil[in_lines[i].instrIndex] # type: ignore
- else:
- il_instr = None
- color = highlight.HighlightColor._from_core_struct(in_lines[i].highlight)
- tokens = function.InstructionTextToken._from_core_struct(in_lines[i].tokens, in_lines[i].count)
- lines.append(function.DisassemblyTextLine(tokens, addr, il_instr, color))
-
- lines = self.format_lines(lines, settings)
-
- out_count[0] = len(lines)
- self.line_buf = (core.BNDisassemblyTextLine * len(lines))()
- for i in range(len(lines)):
- line = lines[i]
- color = line.highlight
- if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor):
- raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor")
- if isinstance(color, HighlightStandardColor):
- color = highlight.HighlightColor(color)
- self.line_buf[i].highlight = color._to_core_struct()
- if line.address is None:
- if len(line.tokens) > 0:
- self.line_buf[i].addr = line.tokens[0].address
- else:
- self.line_buf[i].addr = 0
- else:
- self.line_buf[i].addr = line.address
- if line.il_instruction is not None:
- self.line_buf[i].instrIndex = line.il_instruction.instr_index
- else:
- self.line_buf[i].instrIndex = 0xffffffffffffffff
-
- self.line_buf[i].count = len(line.tokens)
- self.line_buf[i].tokens = function.InstructionTextToken._get_core_struct(line.tokens)
-
- return ctypes.cast(self.line_buf, ctypes.c_void_p).value
- except:
- log_error(traceback.format_exc())
- out_count[0] = 0
- return None
-
- def _free_lines(self, ctxt, lines, count):
- self.line_buf = None
-
- def format_lines(
- self, in_lines: List['function.DisassemblyTextLine'], settings: 'LineFormatterSettings'
- ) -> List['function.DisassemblyTextLine']:
- """
- Reformats the given list of lines. Returns a new list of lines containing the reformatted code.
- """
- raise NotImplementedError
-
- @property
- def name(self) -> str:
- if hasattr(self, 'handle'):
- return core.BNGetLineFormatterName(self.handle)
- return self.__class__.formatter_name
-
- def __repr__(self):
- return f"<LineFormatter: {self.name}>"
-
-
-_formatter_cache = {}
-
-
-class CoreLineFormatter(LineFormatter):
- def __init__(self, handle: core.BNLineFormatter):
- super(CoreLineFormatter, self).__init__(handle=handle)
- if type(self) is CoreLineFormatter:
- global _formatter_cache
- _formatter_cache[ctypes.addressof(handle.contents)] = self
-
- def format_lines(
- self, in_lines: List['function.DisassemblyTextLine'], settings: 'LineFormatterSettings'
- ) -> List['function.DisassemblyTextLine']:
- line_buf = (core.BNDisassemblyTextLine * len(in_lines))()
- for i in range(len(in_lines)):
- line = in_lines[i]
- color = line.highlight
- if not isinstance(color, HighlightStandardColor) and not isinstance(color, highlight.HighlightColor):
- raise ValueError("Specified color is not one of HighlightStandardColor, highlight.HighlightColor")
- if isinstance(color, HighlightStandardColor):
- color = highlight.HighlightColor(color)
- line_buf[i].highlight = color._to_core_struct()
- if line.address is None:
- if len(line.tokens) > 0:
- line_buf[i].addr = line.tokens[0].address
- else:
- line_buf[i].addr = 0
- else:
- line_buf[i].addr = line.address
- if line.il_instruction is not None:
- line_buf[i].instrIndex = line.il_instruction.instr_index
- else:
- line_buf[i].instrIndex = 0xffffffffffffffff
-
- line_buf[i].count = len(line.tokens)
- line_buf[i].tokens = function.InstructionTextToken._get_core_struct(line.tokens)
-
- count = ctypes.c_ulonglong()
- lines = core.BNFormatLines(self.handle, line_buf, len(in_lines), settings._to_core_struct(), count)
-
- result = []
- if lines is not None:
- result = []
- for i in range(0, count.value):
- addr = lines[i].addr
- if lines[i].instrIndex != 0xffffffffffffffff:
- il_instr = settings.hlil[lines[i].instrIndex] # type: ignore
- else:
- il_instr = None
- color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
- tokens = function.InstructionTextToken._from_core_struct(lines[i].tokens, lines[i].count)
- result.append(function.DisassemblyTextLine(tokens, addr, il_instr, color))
- core.BNFreeDisassemblyTextLines(lines, count.value)
- return result
-
- @classmethod
- def _from_cache(cls, handle) -> 'LineFormatter':
- """
- Look up a representation type from a given BNLineFormatter handle
- :param handle: BNLineFormatter pointer
- :return: Formatter instance responsible for this handle
- """
- global _formatter_cache
- return _formatter_cache.get(ctypes.addressof(handle.contents)) or cls(handle)