summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.h3
-rw-r--r--binaryninjacore.h2
-rw-r--r--binaryview.cpp21
-rw-r--r--function.cpp19
-rw-r--r--python/binaryview.py44
-rw-r--r--ui/clickablelabel.h17
-rw-r--r--ui/commands.h5
-rw-r--r--ui/flowgraphwidget.h2
-rw-r--r--ui/linearview.h2
-rw-r--r--ui/possiblevaluesetdialog.h60
-rw-r--r--ui/typedialog.h2
11 files changed, 167 insertions, 10 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 99d74b16..d399a71c 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -1370,6 +1370,7 @@ __attribute__ ((format (printf, 1, 2)))
};
struct QualifiedNameAndType;
+ struct PossibleValueSet;
class Metadata;
class QueryMetadataException: public std::exception
{
@@ -1659,6 +1660,8 @@ __attribute__ ((format (printf, 1, 2)))
uint64_t GetPreviousDataBeforeAddress(uint64_t addr);
uint64_t GetPreviousDataVariableStartBeforeAddress(uint64_t addr);
+ bool ParsePossibleValueSetString(const std::string& value, BNRegisterValueType state, PossibleValueSet& result, uint64_t here, std::string& errors);
+
bool ParseTypeString(const std::string& text, QualifiedNameAndType& result, std::string& errors,
const std::set<QualifiedName>& typesAllowRedefinition = {});
bool ParseTypeString(const std::string& text, std::map<QualifiedName, Ref<Type>>& types,
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 9a93f367..bf691026 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -3390,6 +3390,8 @@ __attribute__ ((format (printf, 1, 2)))
BINARYNINJACOREAPI void BNClearUserVariableValue(BNFunction* func, const BNVariable* var, const BNArchitectureAndAddress* defSite);
BINARYNINJACOREAPI BNUserVariableValue* BNGetAllUserVariableValues(BNFunction *func, size_t* count);
BINARYNINJACOREAPI void BNFreeUserVariableValues(BNUserVariableValue* result);
+ BINARYNINJACOREAPI bool BNParsePossibleValueSetString(BNBinaryView* view, const char* valueText, BNRegisterValueType state,
+ BNPossibleValueSet* result, uint64_t here, char** errors);
BINARYNINJACOREAPI void BNRequestFunctionDebugReport(BNFunction* func, const char* name);
diff --git a/binaryview.cpp b/binaryview.cpp
index 8d78c4b3..3953cee6 100644
--- a/binaryview.cpp
+++ b/binaryview.cpp
@@ -2446,6 +2446,27 @@ uint64_t BinaryView::GetPreviousDataVariableStartBeforeAddress(uint64_t addr)
}
+bool BinaryView::ParsePossibleValueSetString(const string& value, BNRegisterValueType state, PossibleValueSet& result, uint64_t here, string& errors)
+{
+ BNPossibleValueSet res;
+ char* errorStr;
+
+ if (!BNParsePossibleValueSetString(m_object, value.c_str(), state, &res, here, &errorStr))
+ {
+ if (!errorStr)
+ errors = "";
+ else
+ errors = errorStr;
+ BNFreeString(errorStr);
+ return false;
+ }
+
+ result = PossibleValueSet::FromAPIObject(res);
+ errors = "";
+ return true;
+}
+
+
bool BinaryView::ParseTypeString(const string& text, QualifiedNameAndType& result, string& errors,
const std::set<QualifiedName>& typesAllowRedefinition)
{
diff --git a/function.cpp b/function.cpp
index ecb81a67..168decc2 100644
--- a/function.cpp
+++ b/function.cpp
@@ -1773,17 +1773,18 @@ Ref<FlowGraph> Function::GetUnresolvedStackAdjustmentGraph()
void Function::SetUserVariableValue(const Variable& var, uint64_t defAddr, PossibleValueSet& value)
{
- auto mlil = GetMediumLevelIL();
- auto varDefs = mlil->GetVariableDefinitions(var);
+ Ref<MediumLevelILFunction> mlil = GetMediumLevelIL();
+ const set<size_t>& varDefs = mlil->GetVariableDefinitions(var);
if (varDefs.size() == 0)
{
LogError("Could not get definition for Variable");
return;
}
bool found = false;
- for (const auto& site : varDefs)
+ for (auto& site : varDefs)
{
- if (site == defAddr)
+ const MediumLevelILInstruction& instr = mlil->GetInstruction(site);
+ if (instr.address == defAddr)
{
found = true;
break;
@@ -1810,16 +1811,18 @@ void Function::SetUserVariableValue(const Variable& var, uint64_t defAddr, Possi
void Function::ClearUserVariableValue(const Variable& var, uint64_t defAddr)
{
- auto mlil = GetMediumLevelIL();
- auto varDefs = mlil->GetVariableDefinitions(var);
+ Ref<MediumLevelILFunction> mlil = GetMediumLevelIL();
+ const set<size_t>& varDefs = mlil->GetVariableDefinitions(var);
if (varDefs.size() == 0)
{
LogError("Could not get definition for Variable");
+ return;
}
bool found = false;
- for (auto site : varDefs)
+ for (auto& site : varDefs)
{
- if (site == defAddr)
+ const MediumLevelILInstruction& instr = mlil->GetInstruction(site);
+ if (instr.address == defAddr)
{
found = true;
break;
diff --git a/python/binaryview.py b/python/binaryview.py
index 1cd57bf9..39af851c 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -4677,6 +4677,50 @@ class BinaryView(object):
core.BNFreeTypeParserResult(parse)
return types.TypeParserResult(type_dict, variables, functions)
+ def parse_possiblevalueset_string(self, value, state, here=0):
+ r"""
+ Evaluates a string representation of a PossibleValueSet into an instance of the ``PossibleValueSet`` value.
+
+ .. note:: Values are evaluated based on the rules as specified for :py:meth:`parse_expression` API. This implies that a ``ConstantValue [0x4000].d`` can be provided given that 4 bytes can be read at ``0x4000``. All constants are considered to be in hexadecimal form by default.
+
+ The parser uses the following rules:
+ - ConstantValue - ``<value>``
+ - ConstantPointerValue - ``<value>``
+ - StackFrameOffset - ``<value>``
+ - SignedRangeValue - ``<value>:<value>:<value>{,<value>:<value>:<value>}*`` (Multiple ValueRanges can be provided by separating them by commas)
+ - UnsignedRangeValue - ``<value>:<value>:<value>{,<value>:<value>:<value>}*`` (Multiple ValueRanges can be provided by separating them by commas)
+ - InSetOfValues - ``<value>{,<value>}*``
+ - NotInSetOfValues - ``<value>{,<value>}*``
+
+ :param str value: PossibleValueSet value to be parsed
+ :param RegisterValueType state: State for which the value is to be parsed
+ :param int here: (optional) Base address for relative expressions, defaults to zero
+ :rtype: PossibleValueSet
+ :Example:
+
+ >>> psv_c = bv.parse_possiblevalueset_string("400", RegisterValueType.ConstantValue)
+ >>> psv_c
+ <const 0x400>
+ >>> psv_ur = bv.parse_possiblevalueset_string("1:10:1", RegisterValueType.UnsignedRangeValue)
+ >>> psv_ur
+ <unsigned ranges: [<range: 0x1 to 0x10>]>
+ >>> psv_is = bv.parse_possiblevalueset_string("1,2,3", RegisterValueType.InSetOfValues)
+ >>> psv_is
+ <in set([0x1, 0x2, 0x3])>
+ >>>
+ """
+ result = core.BNPossibleValueSet();
+ errors = ctypes.c_char_p();
+ if not core.BNParsePossibleValueSetString(self.handle, value, state, result, here, errors):
+ if errors:
+ error_str = errors.value.decode("utf-8")
+ else:
+ error_str = "Error parsing specified PossibleValueSet"
+ core.BNFreePossibleValueSet(result)
+ core.BNFreeString(ctypes.cast(errors, ctypes.POINTER(ctypes.c_byte)))
+ raise ValueError(error_str)
+ return function.PossibleValueSet(self.arch, result)
+
def get_type_by_name(self, name):
"""
``get_type_by_name`` returns the defined type whose name corresponds with the provided ``name``
diff --git a/ui/clickablelabel.h b/ui/clickablelabel.h
new file mode 100644
index 00000000..df261494
--- /dev/null
+++ b/ui/clickablelabel.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <QtWidgets/QLabel>
+
+class BINARYNINJAUIAPI ClickableLabel: public QLabel
+{
+ Q_OBJECT
+
+public:
+ ClickableLabel(QWidget* parent = nullptr, const QString& name = ""): QLabel(parent) { setText(name); }
+
+signals:
+ void clicked();
+
+protected:
+ void mouseReleaseEvent(QMouseEvent* event) override { if (event->button() == Qt::LeftButton) emit clicked(); }
+};
diff --git a/ui/commands.h b/ui/commands.h
index cdbf16ff..d033fd21 100644
--- a/ui/commands.h
+++ b/ui/commands.h
@@ -22,6 +22,9 @@ bool BINARYNINJAUIAPI inputNewType(QWidget* parent, BinaryViewRef data, Function
bool BINARYNINJAUIAPI createInferredMember(QWidget* parent, BinaryViewRef data, HighlightTokenState& highlight,
FunctionRef func, BNFunctionGraphType type);
+bool BINARYNINJAUIAPI inputPossibleValueSet(QWidget* parent, BinaryViewRef data, FunctionRef currentFunction,
+ HighlightTokenState& highlight, uint64_t defSiteAddress);
+
bool BINARYNINJAUIAPI overwriteCode(BinaryViewRef data, ArchitectureRef arch,
uint64_t addr, size_t len, const BinaryNinja::DataBuffer& buffer);
bool BINARYNINJAUIAPI overwriteCode(BinaryViewRef data, ArchitectureRef arch,
@@ -33,4 +36,4 @@ StructureRef BINARYNINJAUIAPI getInnerMostStructureContainingOffset(BinaryViewRe
const std::vector<std::string>& nameList, size_t nameIndex, size_t& offset, TypeRef& type, std::string& typeName);
// Auto generate a structure name
-std::string BINARYNINJAUIAPI createStructureName(BinaryViewRef data); \ No newline at end of file
+std::string BINARYNINJAUIAPI createStructureName(BinaryViewRef data);
diff --git a/ui/flowgraphwidget.h b/ui/flowgraphwidget.h
index 2a3a8b78..a6e02076 100644
--- a/ui/flowgraphwidget.h
+++ b/ui/flowgraphwidget.h
@@ -284,6 +284,8 @@ private Q_SLOTS:
void followPointer();
void defineName();
void undefineName();
+ void setUserVariableValue();
+ void clearUserVariableValue();
void defineFuncName();
void undefineFunc();
void createFunc();
diff --git a/ui/linearview.h b/ui/linearview.h
index 26c3e9d8..00f02c76 100644
--- a/ui/linearview.h
+++ b/ui/linearview.h
@@ -197,6 +197,8 @@ private Q_SLOTS:
void defineNameAtAddr(uint64_t addr);
void defineName();
void undefineName();
+ void setUserVariableValue();
+ void clearUserVariableValue();
void createFunc();
void createFuncWithPlatform(PlatformRef platform);
void defineFuncName();
diff --git a/ui/possiblevaluesetdialog.h b/ui/possiblevaluesetdialog.h
new file mode 100644
index 00000000..5b5550a3
--- /dev/null
+++ b/ui/possiblevaluesetdialog.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include <QtWidgets/QDialog>
+#include <QtWidgets/QLabel>
+#include <QtCore/QStringListModel>
+#include <QtWidgets/QComboBox>
+#include <QtWidgets/QLineEdit>
+#include <QtCore/QTimer>
+#include <QtCore/QThread>
+#include <QToolTip>
+#include "binaryninjaapi.h"
+#include "dialogtextedit.h"
+#include "clickablelabel.h"
+
+class BINARYNINJAUIAPI PossibleValueSetDialog: public QDialog
+{
+ Q_OBJECT
+
+ QComboBox* m_combo;
+ QLineEdit* m_value;
+ QStringListModel* m_model;
+ QLabel* m_prompt;
+ QString m_promptText;
+ ClickableLabel* m_valueLabel;
+ BinaryViewRef m_view;
+ bool m_resultValid;
+ QStringList m_historyEntries;
+ int m_historySize;
+ QFont m_defaultFont;
+ bool m_initialTextSelection;
+ BinaryNinja::PossibleValueSet m_valueSet;
+ QPushButton* m_acceptButton;
+ QPalette m_defaultPalette;
+ QString m_parseError;
+ uint64_t m_here;
+ QTimer* m_updateTimer;
+
+private Q_SLOTS:
+ void accepted();
+ void checkParse();
+ void updateTimerEvent();
+ void showHelp();
+ void stateChanged(const QString&);
+
+public:
+ PossibleValueSetDialog(QWidget* parent, BinaryViewRef view, uint64_t here);
+ BinaryNinja::PossibleValueSet getPossibleValueSet() const { return m_valueSet; }
+ static BNRegisterValueType getRegisterValueTypeFromString(const std::string& stateStr);
+};
+
+static const QStringList valueSets = {
+ "ConstantValue",
+ "ConstantPointerValue",
+ "StackFrameOffset",
+ "SignedRangeValue",
+ "UnsignedRangeValue",
+ "InSetOfValues",
+ "NotInSetOfValues",
+ "UndeterminedValue",
+};
diff --git a/ui/typedialog.h b/ui/typedialog.h
index 34b68c07..00a722bc 100644
--- a/ui/typedialog.h
+++ b/ui/typedialog.h
@@ -64,4 +64,4 @@ public:
const QString& prompt = "Enter Type Name", const QString& existing="");
~TypeDialog() { delete m_updateThread; }
BinaryNinja::QualifiedNameAndType getType() const { return m_type; }
-}; \ No newline at end of file
+};