summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter LaFosse <peter@vector35.com>2018-09-12 17:03:38 -0400
committerPeter LaFosse <peter@vector35.com>2018-09-12 17:03:38 -0400
commit74a8547853dd66fe62d2e75b93c1b723eb6f69cf (patch)
tree067119496c2beaf0636c955d27291d4620e17c0b
parent097a2e4c8849d4938d8a027985ce3816fd9785ed (diff)
parent59a2824b1ad36ea5d0520919e86ad779cd97cc8f (diff)
Merging with dev
-rw-r--r--basicblock.cpp16
-rw-r--r--binaryninjaapi.h192
-rw-r--r--binaryninjacore.h236
-rw-r--r--binaryview.cpp8
-rw-r--r--docs/getting-started.md14
-rw-r--r--flowgraph.cpp358
-rw-r--r--flowgraphnode.cpp206
-rw-r--r--function.cpp70
-rw-r--r--functiongraph.cpp224
-rw-r--r--functiongraphblock.cpp146
-rw-r--r--interaction.cpp140
-rw-r--r--lowlevelil.cpp7
-rw-r--r--lowlevelilinstruction.cpp6
-rw-r--r--lowlevelilinstruction.h6
-rw-r--r--mediumlevelil.cpp7
-rw-r--r--mediumlevelilinstruction.cpp9
-rw-r--r--mediumlevelilinstruction.h4
-rw-r--r--python/__init__.py2
-rw-r--r--python/basicblock.py12
-rw-r--r--python/binaryview.py7
-rw-r--r--python/flowgraph.py633
-rw-r--r--python/function.py437
-rw-r--r--python/highlight.py10
-rw-r--r--python/interaction.py173
-rw-r--r--python/lowlevelil.py14
-rw-r--r--python/mainthread.py3
-rw-r--r--python/mediumlevelil.py16
-rw-r--r--python/types.py2
-rw-r--r--type.cpp10
29 files changed, 2025 insertions, 943 deletions
diff --git a/basicblock.cpp b/basicblock.cpp
index 13b3e7a8..9fc8d8aa 100644
--- a/basicblock.cpp
+++ b/basicblock.cpp
@@ -72,6 +72,21 @@ void DisassemblySettings::SetMaximumSymbolWidth(size_t width)
}
+DisassemblyTextLine::DisassemblyTextLine()
+{
+ addr = 0;
+ instrIndex = BN_INVALID_EXPR;
+ highlight.style = StandardHighlightColor;
+ highlight.color = NoHighlightColor;
+ highlight.mixColor = NoHighlightColor;
+ highlight.mix = 0;
+ highlight.r = 0;
+ highlight.g = 0;
+ highlight.b = 0;
+ highlight.alpha = 0;
+}
+
+
BasicBlock::BasicBlock(BNBasicBlock* block)
{
m_object = block;
@@ -277,6 +292,7 @@ vector<DisassemblyTextLine> BasicBlock::GetDisassemblyText(DisassemblySettings*
DisassemblyTextLine line;
line.addr = lines[i].addr;
line.instrIndex = lines[i].instrIndex;
+ line.highlight = lines[i].highlight;
line.tokens.reserve(lines[i].count);
for (size_t j = 0; j < lines[i].count; j++)
{
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 93fa9eda..647d2677 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -54,6 +54,7 @@ namespace BinaryNinja
virtual ~RefCountObject() {}
RefCountObject* GetObject() { return this; }
+ static RefCountObject* GetObject(RefCountObject* obj) { return obj; }
void AddRef()
{
@@ -107,6 +108,13 @@ namespace BinaryNinja
T* GetObject() const { return m_object; }
+ static T* GetObject(CoreRefCountObject* obj)
+ {
+ if (!obj)
+ return nullptr;
+ return obj->GetObject();
+ }
+
void AddRef()
{
if (m_object && (m_refs != 0))
@@ -164,6 +172,13 @@ namespace BinaryNinja
T* GetObject() const { return m_object; }
+ static T* GetObject(StaticCoreRefCountObject* obj)
+ {
+ if (!obj)
+ return nullptr;
+ return obj->GetObject();
+ }
+
void AddRef()
{
AddRefInternal();
@@ -252,32 +267,32 @@ namespace BinaryNinja
bool operator==(const T* obj) const
{
- return m_obj->GetObject() == obj->GetObject();
+ return T::GetObject(m_obj) == T::GetObject(obj);
}
bool operator==(const Ref<T>& obj) const
{
- return m_obj->GetObject() == obj.m_obj->GetObject();
+ return T::GetObject(m_obj) == T::GetObject(obj.m_obj);
}
bool operator!=(const T* obj) const
{
- return m_obj->GetObject() != obj->GetObject();
+ return T::GetObject(m_obj) != T::GetObject(obj);
}
bool operator!=(const Ref<T>& obj) const
{
- return m_obj->GetObject() != obj.m_obj->GetObject();
+ return T::GetObject(m_obj) != T::GetObject(obj.m_obj);
}
bool operator<(const T* obj) const
{
- return m_obj->GetObject() < obj->GetObject();
+ return T::GetObject(m_obj) < T::GetObject(obj);
}
bool operator<(const Ref<T>& obj) const
{
- return m_obj->GetObject() < obj.m_obj->GetObject();
+ return T::GetObject(m_obj) < T::GetObject(obj.m_obj);
}
T* GetPtr() const
@@ -494,6 +509,8 @@ namespace BinaryNinja
class MainThreadActionHandler;
class InteractionHandler;
class QualifiedName;
+ class FlowGraph;
+ class ReportCollection;
struct FormInputField;
/*! Logs to the error console with the given BNLogLevel.
@@ -627,6 +644,8 @@ namespace BinaryNinja
const std::string& plainText = "");
void ShowHTMLReport(const std::string& title, const std::string& contents,
const std::string& plainText = "");
+ void ShowGraphReport(const std::string& title, FlowGraph* graph);
+ void ShowReportCollection(const std::string& title, ReportCollection* reports);
bool GetTextLineInput(std::string& result, const std::string& prompt, const std::string& title);
bool GetIntegerInput(int64_t& result, const std::string& prompt, const std::string& title);
@@ -940,6 +959,9 @@ namespace BinaryNinja
uint64_t addr;
size_t instrIndex;
std::vector<InstructionTextToken> tokens;
+ BNHighlightColor highlight;
+
+ DisassemblyTextLine();
};
struct LinearDisassemblyPosition
@@ -1321,6 +1343,7 @@ namespace BinaryNinja
void ShowPlainTextReport(const std::string& title, const std::string& contents);
void ShowMarkdownReport(const std::string& title, const std::string& contents, const std::string& plainText);
void ShowHTMLReport(const std::string& title, const std::string& contents, const std::string& plainText);
+ void ShowGraphReport(const std::string& title, FlowGraph* graph);
bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title);
bool GetAddressInput(uint64_t& result, const std::string& prompt, const std::string& title,
uint64_t currentAddress);
@@ -2173,7 +2196,7 @@ namespace BinaryNinja
void SetConst(const Confidence<bool>& cnst);
void SetVolatile(const Confidence<bool>& vltl);
void SetTypeName(const QualifiedName& name);
- Confidence<size_t> GetStackAdjustment() const;
+ Confidence<int64_t> GetStackAdjustment() const;
uint64_t GetElementCount() const;
uint64_t GetOffset() const;
@@ -2214,7 +2237,7 @@ namespace BinaryNinja
static Ref<Type> FunctionType(const Confidence<Ref<Type>>& returnValue,
const Confidence<Ref<CallingConvention>>& callingConvention,
const std::vector<FunctionParameter>& params, const Confidence<bool>& varArg = Confidence<bool>(false, 0),
- const Confidence<size_t>& stackAdjust = Confidence<size_t>(0, 0));
+ const Confidence<int64_t>& stackAdjust = Confidence<int64_t>(0, 0));
static std::string GenerateAutoTypeId(const std::string& source, const QualifiedName& name);
static std::string GenerateAutoDemangledTypeId(const QualifiedName& name);
@@ -2441,7 +2464,7 @@ namespace BinaryNinja
static PossibleValueSet FromAPIObject(BNPossibleValueSet& value);
};
- class FunctionGraph;
+ class FlowGraph;
class MediumLevelILFunction;
class Function: public CoreRefCountObject<BNFunction, BNNewFunctionReference, BNFreeFunction>
@@ -2452,6 +2475,7 @@ namespace BinaryNinja
Function(BNFunction* func);
virtual ~Function();
+ Ref<BinaryView> GetView() const;
Ref<Architecture> GetArchitecture() const;
Ref<Platform> GetPlatform() const;
uint64_t GetStart() const;
@@ -2500,7 +2524,7 @@ namespace BinaryNinja
Confidence<Ref<CallingConvention>> GetCallingConvention() const;
Confidence<std::vector<Variable>> GetParameterVariables() const;
Confidence<bool> HasVariableArguments() const;
- Confidence<size_t> GetStackAdjustment() const;
+ Confidence<int64_t> GetStackAdjustment() const;
std::map<uint32_t, Confidence<int32_t>> GetRegisterStackAdjustments() const;
Confidence<std::set<uint32_t>> GetClobberedRegisters() const;
@@ -2511,7 +2535,7 @@ namespace BinaryNinja
void SetAutoParameterVariables(const Confidence<std::vector<Variable>>& vars);
void SetAutoHasVariableArguments(const Confidence<bool>& varArgs);
void SetAutoCanReturn(const Confidence<bool>& returns);
- void SetAutoStackAdjustment(const Confidence<size_t>& stackAdjust);
+ void SetAutoStackAdjustment(const Confidence<int64_t>& stackAdjust);
void SetAutoRegisterStackAdjustments(const std::map<uint32_t, Confidence<int32_t>>& regStackAdjust);
void SetAutoClobberedRegisters(const Confidence<std::set<uint32_t>>& clobbered);
@@ -2522,14 +2546,14 @@ namespace BinaryNinja
void SetParameterVariables(const Confidence<std::vector<Variable>>& vars);
void SetHasVariableArguments(const Confidence<bool>& varArgs);
void SetCanReturn(const Confidence<bool>& returns);
- void SetStackAdjustment(const Confidence<size_t>& stackAdjust);
+ void SetStackAdjustment(const Confidence<int64_t>& stackAdjust);
void SetRegisterStackAdjustments(const std::map<uint32_t, Confidence<int32_t>>& regStackAdjust);
void SetClobberedRegisters(const Confidence<std::set<uint32_t>>& clobbered);
void ApplyImportedTypes(Symbol* sym);
void ApplyAutoDiscoveredType(Type* type);
- Ref<FunctionGraph> CreateFunctionGraph();
+ Ref<FlowGraph> CreateFunctionGraph(BNFunctionGraphType type, DisassemblySettings* settings = nullptr);
std::map<int64_t, std::vector<VariableNameAndType>> GetStackLayout();
void CreateAutoStackVariable(int64_t offset, const Confidence<Ref<Type>>& type, const std::string& name);
@@ -2554,20 +2578,21 @@ namespace BinaryNinja
std::vector<IndirectBranchInfo> GetIndirectBranches();
std::vector<IndirectBranchInfo> GetIndirectBranchesAt(Architecture* arch, uint64_t addr);
- void SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<size_t>& adjust);
+ void SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<int64_t>& adjust);
void SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr,
const std::map<uint32_t, Confidence<int32_t>>& adjust);
void SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack,
const Confidence<int32_t>& adjust);
- void SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<size_t>& adjust);
+ void SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<int64_t>& adjust);
void SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr,
const std::map<uint32_t, Confidence<int32_t>>& adjust);
void SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack,
const Confidence<int32_t>& adjust);
- Confidence<size_t> GetCallStackAdjustment(Architecture* arch, uint64_t addr);
+ Confidence<int64_t> GetCallStackAdjustment(Architecture* arch, uint64_t addr);
std::map<uint32_t, Confidence<int32_t>> GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr);
Confidence<int32_t> GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack);
+ bool IsCallInstruction(Architecture* arch, uint64_t addr);
std::vector<std::vector<InstructionTextToken>> GetBlockAnnotations(Architecture* arch, uint64_t addr);
@@ -2610,6 +2635,10 @@ namespace BinaryNinja
BNAnalysisSkipReason GetAnalysisSkipReason();
BNFunctionAnalysisSkipOverride GetAnalysisSkipOverride();
void SetAnalysisSkipOverride(BNFunctionAnalysisSkipOverride skip);
+
+ Ref<FlowGraph> GetUnresolvedStackAdjustmentGraph();
+
+ void RequestDebugReport(const std::string& name);
};
class AdvancedFunctionAnalysisDataRequestor
@@ -2626,79 +2655,118 @@ namespace BinaryNinja
void SetFunction(Function* func);
};
- struct FunctionGraphEdge
+ class FlowGraphNode;
+
+ struct FlowGraphEdge
{
BNBranchType type;
- Ref<BasicBlock> target;
+ Ref<FlowGraphNode> target;
std::vector<BNPoint> points;
bool backEdge;
};
- class FunctionGraphBlock: public CoreRefCountObject<BNFunctionGraphBlock,
- BNNewFunctionGraphBlockReference, BNFreeFunctionGraphBlock>
+ class FlowGraphNode: public CoreRefCountObject<BNFlowGraphNode,
+ BNNewFlowGraphNodeReference, BNFreeFlowGraphNode>
{
std::vector<DisassemblyTextLine> m_cachedLines;
- std::vector<FunctionGraphEdge> m_cachedEdges;
+ std::vector<FlowGraphEdge> m_cachedEdges;
bool m_cachedLinesValid, m_cachedEdgesValid;
public:
- FunctionGraphBlock(BNFunctionGraphBlock* block);
+ FlowGraphNode(FlowGraph* graph);
+ FlowGraphNode(BNFlowGraphNode* node);
Ref<BasicBlock> GetBasicBlock() const;
- Ref<Architecture> GetArchitecture() const;
- uint64_t GetStart() const;
- uint64_t GetEnd() const;
+ void SetBasicBlock(BasicBlock* block);
int GetX() const;
int GetY() const;
int GetWidth() const;
int GetHeight() const;
const std::vector<DisassemblyTextLine>& GetLines();
- const std::vector<FunctionGraphEdge>& GetOutgoingEdges();
+ void SetLines(const std::vector<DisassemblyTextLine>& lines);
+ const std::vector<FlowGraphEdge>& GetOutgoingEdges();
+ void AddOutgoingEdge(BNBranchType type, FlowGraphNode* target);
+
+ BNHighlightColor GetHighlight() const;
+ void SetHighlight(const BNHighlightColor& color);
};
- class FunctionGraph: public RefCountObject
+ class FlowGraphLayoutRequest: public RefCountObject
{
- BNFunctionGraph* m_graph;
+ BNFlowGraphLayoutRequest* m_object;
std::function<void()> m_completeFunc;
- std::map<BNFunctionGraphBlock*, Ref<FunctionGraphBlock>> m_cachedBlocks;
static void CompleteCallback(void* ctxt);
public:
- FunctionGraph(BNFunctionGraph* graph);
- ~FunctionGraph();
+ FlowGraphLayoutRequest(FlowGraph* graph, const std::function<void()>& completeFunc);
+ virtual ~FlowGraphLayoutRequest();
- BNFunctionGraph* GetGraphObject() const { return m_graph; }
+ BNFlowGraphLayoutRequest* GetObject() const { return m_object; }
- Ref<Function> GetFunction() const;
+ Ref<FlowGraph> GetGraph() const;
+ bool IsComplete() const;
+ void Abort();
+ };
+
+ class FlowGraph: public CoreRefCountObject<BNFlowGraph, BNNewFlowGraphReference, BNFreeFlowGraph>
+ {
+ std::map<BNFlowGraphNode*, Ref<FlowGraphNode>> m_cachedNodes;
+
+ static void PrepareForLayoutCallback(void* ctxt);
+ static void PopulateNodesCallback(void* ctxt);
+ static void CompleteLayoutCallback(void* ctxt);
+ static BNFlowGraph* UpdateCallback(void* ctxt);
+
+ protected:
+ FlowGraph(BNFlowGraph* graph);
- int GetHorizontalBlockMargin() const;
- int GetVerticalBlockMargin() const;
- void SetBlockMargins(int horiz, int vert);
+ void FinishPrepareForLayout();
+ virtual void PrepareForLayout();
+ virtual void PopulateNodes();
+ virtual void CompleteLayout();
- Ref<DisassemblySettings> GetSettings();
+ public:
+ FlowGraph();
+
+ Ref<Function> GetFunction() const;
+ void SetFunction(Function* func);
+
+ int GetHorizontalNodeMargin() const;
+ int GetVerticalNodeMargin() const;
+ void SetNodeMargins(int horiz, int vert);
- void StartLayout(BNFunctionGraphType = NormalFunctionGraph);
+ Ref<FlowGraphLayoutRequest> StartLayout(const std::function<void()>& func);
bool IsLayoutComplete();
- void OnComplete(const std::function<void()>& func);
- void Abort();
- std::vector<Ref<FunctionGraphBlock>> GetBlocks();
- bool HasBlocks() const;
+ std::vector<Ref<FlowGraphNode>> GetNodes();
+ Ref<FlowGraphNode> GetNode(size_t i);
+ bool HasNodes() const;
+ size_t AddNode(FlowGraphNode* node);
int GetWidth() const;
int GetHeight() const;
- std::vector<Ref<FunctionGraphBlock>> GetBlocksInRegion(int left, int top, int right, int bottom);
-
- bool IsOptionSet(BNDisassemblyOption option) const;
- void SetOption(BNDisassemblyOption option, bool state = true);
+ std::vector<Ref<FlowGraphNode>> GetNodesInRegion(int left, int top, int right, int bottom);
bool IsILGraph() const;
bool IsLowLevelILGraph() const;
bool IsMediumLevelILGraph() const;
Ref<LowLevelILFunction> GetLowLevelILFunction() const;
Ref<MediumLevelILFunction> GetMediumLevelILFunction() const;
+ void SetLowLevelILFunction(LowLevelILFunction* func);
+ void SetMediumLevelILFunction(MediumLevelILFunction* func);
+
+ void Show(const std::string& title);
+
+ virtual Ref<FlowGraph> Update();
+ };
+
+ class CoreFlowGraph: public FlowGraph
+ {
+ public:
+ CoreFlowGraph(BNFlowGraph* graph);
+ virtual Ref<FlowGraph> Update() override;
};
struct LowLevelILLabel: public BNLowLevelILLabel
@@ -2895,7 +2963,7 @@ namespace BinaryNinja
ExprId JumpTo(ExprId dest, const std::vector<BNLowLevelILLabel*>& targets,
const ILSourceLocation& loc = ILSourceLocation());
ExprId Call(ExprId dest, const ILSourceLocation& loc = ILSourceLocation());
- ExprId CallStackAdjust(ExprId dest, size_t adjust, const std::map<uint32_t, int32_t>& regStackAdjust,
+ ExprId CallStackAdjust(ExprId dest, int64_t adjust, const std::map<uint32_t, int32_t>& regStackAdjust,
const ILSourceLocation& loc = ILSourceLocation());
ExprId TailCall(ExprId dest, const ILSourceLocation& loc = ILSourceLocation());
ExprId CallSSA(const std::vector<SSARegister>& output, ExprId dest, const std::vector<ExprId>& params,
@@ -3073,6 +3141,8 @@ namespace BinaryNinja
size_t GetMappedMediumLevelILExprIndex(size_t expr) const;
static bool IsConstantType(BNLowLevelILOperation type) { return type == LLIL_CONST || type == LLIL_CONST_PTR || type == LLIL_EXTERN_PTR; }
+
+ Ref<FlowGraph> CreateFunctionGraph(DisassemblySettings* settings = nullptr);
};
struct MediumLevelILLabel: public BNMediumLevelILLabel
@@ -3216,6 +3286,7 @@ namespace BinaryNinja
ExprId Jump(ExprId dest, const ILSourceLocation& loc = ILSourceLocation());
ExprId JumpTo(ExprId dest, const std::vector<BNMediumLevelILLabel*>& targets,
const ILSourceLocation& loc = ILSourceLocation());
+ ExprId ReturnHint(ExprId dest, const ILSourceLocation& loc = ILSourceLocation());
ExprId Call(const std::vector<Variable>& output, ExprId dest, const std::vector<ExprId>& params,
const ILSourceLocation& loc = ILSourceLocation());
ExprId CallUntyped(const std::vector<Variable>& output, ExprId dest, const std::vector<Variable>& params,
@@ -3406,6 +3477,8 @@ namespace BinaryNinja
Confidence<Ref<Type>> GetExprType(const MediumLevelILInstruction& expr);
static bool IsConstantType(BNMediumLevelILOperation op) { return op == MLIL_CONST || op == MLIL_CONST_PTR || op == MLIL_EXTERN_PTR; }
+
+ Ref<FlowGraph> CreateFunctionGraph(DisassemblySettings* settings = nullptr);
};
class FunctionRecognizer
@@ -4009,6 +4082,29 @@ namespace BinaryNinja
static FormInputField DirectoryName(const std::string& prompt, const std::string& defaultName = "");
};
+ class ReportCollection: public CoreRefCountObject<BNReportCollection,
+ BNNewReportCollectionReference, BNFreeReportCollection>
+ {
+ public:
+ ReportCollection();
+ ReportCollection(BNReportCollection* reports);
+
+ size_t GetCount() const;
+ BNReportType GetType(size_t i) const;
+ Ref<BinaryView> GetView(size_t i) const;
+ std::string GetTitle(size_t i) const;
+ std::string GetContents(size_t i) const;
+ std::string GetPlainText(size_t i) const;
+ Ref<FlowGraph> GetFlowGraph(size_t i) const;
+
+ void AddPlainTextReport(Ref<BinaryView> view, const std::string& title, const std::string& contents);
+ void AddMarkdownReport(Ref<BinaryView> view, const std::string& title, const std::string& contents,
+ const std::string& plainText = "");
+ void AddHTMLReport(Ref<BinaryView> view, const std::string& title, const std::string& contents,
+ const std::string& plainText = "");
+ void AddGraphReport(Ref<BinaryView> view, const std::string& title, Ref<FlowGraph> graph);
+ };
+
class InteractionHandler
{
public:
@@ -4017,6 +4113,8 @@ namespace BinaryNinja
const std::string& plainText);
virtual void ShowHTMLReport(Ref<BinaryView> view, const std::string& title, const std::string& contents,
const std::string& plainText);
+ virtual void ShowGraphReport(Ref<BinaryView> view, const std::string& title, Ref<FlowGraph> graph);
+ virtual void ShowReportCollection(const std::string& title, Ref<ReportCollection> reports);
virtual bool GetTextLineInput(std::string& result, const std::string& prompt, const std::string& title) = 0;
virtual bool GetIntegerInput(int64_t& result, const std::string& prompt, const std::string& title);
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 6597b335..984fb43b 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -124,8 +124,9 @@ extern "C"
struct BNBasicBlock;
struct BNDownloadProvider;
struct BNDownloadInstance;
- struct BNFunctionGraph;
- struct BNFunctionGraphBlock;
+ struct BNFlowGraph;
+ struct BNFlowGraphNode;
+ struct BNFlowGraphLayoutRequest;
struct BNSymbol;
struct BNTemporaryFile;
struct BNLowLevelILFunction;
@@ -146,6 +147,7 @@ extern "C"
struct BNRepoPlugin;
struct BNRepositoryManager;
struct BNMetadata;
+ struct BNReportCollection;
struct BNRelocation;
struct BNSegment;
struct BNSection;
@@ -874,6 +876,7 @@ extern "C"
MLIL_LOW_PART,
MLIL_JUMP,
MLIL_JUMP_TO,
+ MLIL_RET_HINT, // Intermediate stages, does not appear in final forms
MLIL_CALL, // Not valid in SSA form (see MLIL_CALL_SSA)
MLIL_CALL_UNTYPED, // Not valid in SSA form (see MLIL_CALL_UNTYPED_SSA)
MLIL_CALL_OUTPUT, // Only valid within MLIL_CALL, MLIL_SYSCALL, MLIL_TAILCALL family instructions
@@ -1275,21 +1278,51 @@ extern "C"
float y;
};
- struct BNFunctionGraphEdge
+ struct BNFlowGraphEdge
{
BNBranchType type;
- BNBasicBlock* target;
+ BNFlowGraphNode* target;
BNPoint* points;
size_t pointCount;
bool backEdge;
};
+ enum BNHighlightColorStyle
+ {
+ StandardHighlightColor = 0,
+ MixedHighlightColor = 1,
+ CustomHighlightColor = 2
+ };
+
+ enum BNHighlightStandardColor
+ {
+ NoHighlightColor = 0,
+ BlueHighlightColor = 1,
+ GreenHighlightColor = 2,
+ CyanHighlightColor = 3,
+ RedHighlightColor = 4,
+ MagentaHighlightColor = 5,
+ YellowHighlightColor = 6,
+ OrangeHighlightColor = 7,
+ WhiteHighlightColor = 8,
+ BlackHighlightColor = 9
+ };
+
+ struct BNHighlightColor
+ {
+ BNHighlightColorStyle style;
+ BNHighlightStandardColor color;
+ BNHighlightStandardColor mixColor;
+ uint8_t mix, r, g, b, alpha;
+ };
+
struct BNDisassemblyTextLine
{
uint64_t addr;
size_t instrIndex;
BNInstructionTextToken* tokens;
size_t count;
+ BNHighlightColor highlight;
};
struct BNLinearDisassemblyLine
@@ -1343,6 +1376,12 @@ extern "C"
uint8_t confidence;
};
+ struct BNOffsetWithConfidence
+ {
+ int64_t value;
+ uint8_t confidence;
+ };
+
struct BNMemberScopeWithConfidence
{
BNMemberScope value;
@@ -1688,35 +1727,6 @@ extern "C"
BNMetadata** values;
};
- enum BNHighlightColorStyle
- {
- StandardHighlightColor = 0,
- MixedHighlightColor = 1,
- CustomHighlightColor = 2
- };
-
- enum BNHighlightStandardColor
- {
- NoHighlightColor = 0,
- BlueHighlightColor = 1,
- GreenHighlightColor = 2,
- CyanHighlightColor = 3,
- RedHighlightColor = 4,
- MagentaHighlightColor = 5,
- YellowHighlightColor = 6,
- OrangeHighlightColor = 7,
- WhiteHighlightColor = 8,
- BlackHighlightColor = 9
- };
-
- struct BNHighlightColor
- {
- BNHighlightColorStyle style;
- BNHighlightStandardColor color;
- BNHighlightStandardColor mixColor;
- uint8_t mix, r, g, b, alpha;
- };
-
enum BNMessageBoxIcon
{
InformationIcon,
@@ -1778,6 +1788,8 @@ extern "C"
const char* plaintext);
void (*showHTMLReport)(void* ctxt, BNBinaryView* view, const char* title, const char* contents,
const char* plaintext);
+ void (*showGraphReport)(void* ctxt, BNBinaryView* view, const char* title, BNFlowGraph* graph);
+ void (*showReportCollection)(void* ctxt, const char* title, BNReportCollection* reports);
bool (*getTextLineInput)(void* ctxt, char** result, const char* prompt, const char* title);
bool (*getIntegerInput)(void* ctxt, int64_t* result, const char* prompt, const char* title);
bool (*getAddressInput)(void* ctxt, uint64_t* result, const char* prompt, const char* title,
@@ -1883,6 +1895,23 @@ extern "C"
AlwaysSkipFunctionAnalysis
};
+ enum BNReportType
+ {
+ PlainTextReportType,
+ MarkdownReportType,
+ HTMLReportType,
+ FlowGraphReportType
+ };
+
+ struct BNCustomFlowGraph
+ {
+ void* context;
+ void (*prepareForLayout)(void* ctxt);
+ void (*populateNodes)(void* ctxt);
+ void (*completeLayout)(void* ctxt);
+ BNFlowGraph* (*update)(void* ctxt);
+ };
+
struct BNRange
{
uint64_t start;
@@ -2462,7 +2491,7 @@ extern "C"
BINARYNINJACOREAPI BNParameterVariablesWithConfidence BNGetFunctionParameterVariables(BNFunction* func);
BINARYNINJACOREAPI void BNFreeParameterVariables(BNParameterVariablesWithConfidence* vars);
BINARYNINJACOREAPI BNBoolWithConfidence BNFunctionHasVariableArguments(BNFunction* func);
- BINARYNINJACOREAPI BNSizeWithConfidence BNGetFunctionStackAdjustment(BNFunction* func);
+ BINARYNINJACOREAPI BNOffsetWithConfidence BNGetFunctionStackAdjustment(BNFunction* func);
BINARYNINJACOREAPI BNRegisterStackAdjustment* BNGetFunctionRegisterStackAdjustments(BNFunction* func, size_t* count);
BINARYNINJACOREAPI void BNFreeRegisterStackAdjustments(BNRegisterStackAdjustment* adjustments);
BINARYNINJACOREAPI BNRegisterSetWithConfidence BNGetFunctionClobberedRegisters(BNFunction* func);
@@ -2474,7 +2503,7 @@ extern "C"
BINARYNINJACOREAPI void BNSetAutoFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars);
BINARYNINJACOREAPI void BNSetAutoFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs);
BINARYNINJACOREAPI void BNSetAutoFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns);
- BINARYNINJACOREAPI void BNSetAutoFunctionStackAdjustment(BNFunction* func, BNSizeWithConfidence* stackAdjust);
+ BINARYNINJACOREAPI void BNSetAutoFunctionStackAdjustment(BNFunction* func, BNOffsetWithConfidence* stackAdjust);
BINARYNINJACOREAPI void BNSetAutoFunctionRegisterStackAdjustments(BNFunction* func,
BNRegisterStackAdjustment* adjustments, size_t count);
BINARYNINJACOREAPI void BNSetAutoFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs);
@@ -2485,7 +2514,7 @@ extern "C"
BINARYNINJACOREAPI void BNSetUserFunctionParameterVariables(BNFunction* func, BNParameterVariablesWithConfidence* vars);
BINARYNINJACOREAPI void BNSetUserFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs);
BINARYNINJACOREAPI void BNSetUserFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns);
- BINARYNINJACOREAPI void BNSetUserFunctionStackAdjustment(BNFunction* func, BNSizeWithConfidence* stackAdjust);
+ BINARYNINJACOREAPI void BNSetUserFunctionStackAdjustment(BNFunction* func, BNOffsetWithConfidence* stackAdjust);
BINARYNINJACOREAPI void BNSetUserFunctionRegisterStackAdjustments(BNFunction* func,
BNRegisterStackAdjustment* adjustments, size_t count);
BINARYNINJACOREAPI void BNSetUserFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs);
@@ -2578,9 +2607,9 @@ extern "C"
BINARYNINJACOREAPI void BNFreeIndirectBranchList(BNIndirectBranchInfo* branches);
BINARYNINJACOREAPI void BNSetAutoCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr,
- size_t adjust, uint8_t confidence);
+ int64_t adjust, uint8_t confidence);
BINARYNINJACOREAPI void BNSetUserCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr,
- size_t adjust, uint8_t confidence);
+ int64_t adjust, uint8_t confidence);
BINARYNINJACOREAPI void BNSetAutoCallRegisterStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr,
BNRegisterStackAdjustment* adjust, size_t count);
BINARYNINJACOREAPI void BNSetUserCallRegisterStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr,
@@ -2590,11 +2619,12 @@ extern "C"
BINARYNINJACOREAPI void BNSetUserCallRegisterStackAdjustmentForRegisterStack(BNFunction* func,
BNArchitecture* arch, uint64_t addr, uint32_t regStack, int32_t adjust, uint8_t confidence);
- BINARYNINJACOREAPI BNSizeWithConfidence BNGetCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr);
+ BINARYNINJACOREAPI BNOffsetWithConfidence BNGetCallStackAdjustment(BNFunction* func, BNArchitecture* arch, uint64_t addr);
BINARYNINJACOREAPI BNRegisterStackAdjustment* BNGetCallRegisterStackAdjustment(BNFunction* func,
BNArchitecture* arch, uint64_t addr, size_t* count);
BINARYNINJACOREAPI BNRegisterStackAdjustment BNGetCallRegisterStackAdjustmentForRegisterStack(BNFunction* func,
BNArchitecture* arch, uint64_t addr, uint32_t regStack);
+ BINARYNINJACOREAPI bool BNIsCallInstruction(BNFunction* func, BNArchitecture* arch, uint64_t addr);
BINARYNINJACOREAPI BNInstructionTextLine* BNGetFunctionBlockAnnotations(BNFunction* func, BNArchitecture* arch,
uint64_t addr, size_t* count);
@@ -2698,6 +2728,10 @@ extern "C"
BINARYNINJACOREAPI BNPerformanceInfo* BNGetFunctionAnalysisPerformanceInfo(BNFunction* func, size_t* count);
BINARYNINJACOREAPI void BNFreeAnalysisPerformanceInfo(BNPerformanceInfo* info, size_t count);
+ BINARYNINJACOREAPI BNFlowGraph* BNGetUnresolvedStackAdjustmentGraph(BNFunction* func);
+
+ BINARYNINJACOREAPI void BNRequestFunctionDebugReport(BNFunction* func, const char* name);
+
// Disassembly settings
BINARYNINJACOREAPI BNDisassemblySettings* BNCreateDisassemblySettings(void);
BINARYNINJACOREAPI BNDisassemblySettings* BNNewDisassemblySettingsReference(BNDisassemblySettings* settings);
@@ -2713,56 +2747,73 @@ extern "C"
BINARYNINJACOREAPI size_t BNGetDisassemblyMaximumSymbolWidth(BNDisassemblySettings* settings);
BINARYNINJACOREAPI void BNSetDisassemblyMaximumSymbolWidth(BNDisassemblySettings* settings, size_t width);
- // Function graph
- BINARYNINJACOREAPI BNFunctionGraph* BNCreateFunctionGraph(BNFunction* func);
- BINARYNINJACOREAPI BNFunctionGraph* BNNewFunctionGraphReference(BNFunctionGraph* graph);
- BINARYNINJACOREAPI void BNFreeFunctionGraph(BNFunctionGraph* graph);
- BINARYNINJACOREAPI BNFunction* BNGetFunctionForFunctionGraph(BNFunctionGraph* graph);
+ // Flow graphs
+ BINARYNINJACOREAPI BNFlowGraph* BNCreateFlowGraph();
+ BINARYNINJACOREAPI BNFlowGraph* BNCreateFunctionGraph(BNFunction* func, BNFunctionGraphType type,
+ BNDisassemblySettings* settings);
+ BINARYNINJACOREAPI BNFlowGraph* BNCreateLowLevelILFunctionGraph(BNLowLevelILFunction* func,
+ BNDisassemblySettings* settings);
+ BINARYNINJACOREAPI BNFlowGraph* BNCreateMediumLevelILFunctionGraph(BNMediumLevelILFunction* func,
+ BNDisassemblySettings* settings);
+ BINARYNINJACOREAPI BNFlowGraph* BNCreateCustomFlowGraph(BNCustomFlowGraph* callbacks);
+ BINARYNINJACOREAPI BNFlowGraph* BNNewFlowGraphReference(BNFlowGraph* graph);
+ BINARYNINJACOREAPI void BNFreeFlowGraph(BNFlowGraph* graph);
+ BINARYNINJACOREAPI BNFunction* BNGetFunctionForFlowGraph(BNFlowGraph* graph);
+ BINARYNINJACOREAPI void BNSetFunctionForFlowGraph(BNFlowGraph* graph, BNFunction* func);
- BINARYNINJACOREAPI int BNGetHorizontalFunctionGraphBlockMargin(BNFunctionGraph* graph);
- BINARYNINJACOREAPI int BNGetVerticalFunctionGraphBlockMargin(BNFunctionGraph* graph);
- BINARYNINJACOREAPI void BNSetFunctionGraphBlockMargins(BNFunctionGraph* graph, int horiz, int vert);
+ BINARYNINJACOREAPI int BNGetHorizontalFlowGraphNodeMargin(BNFlowGraph* graph);
+ BINARYNINJACOREAPI int BNGetVerticalFlowGraphNodeMargin(BNFlowGraph* graph);
+ BINARYNINJACOREAPI void BNSetFlowGraphNodeMargins(BNFlowGraph* graph, int horiz, int vert);
- BINARYNINJACOREAPI BNDisassemblySettings* BNGetFunctionGraphSettings(BNFunctionGraph* graph);
+ BINARYNINJACOREAPI BNFlowGraphLayoutRequest* BNStartFlowGraphLayout(BNFlowGraph* graph, void* ctxt, void (*func)(void* ctxt));
+ BINARYNINJACOREAPI bool BNIsFlowGraphLayoutComplete(BNFlowGraph* graph);
+ BINARYNINJACOREAPI BNFlowGraphLayoutRequest* BNNewFlowGraphLayoutRequestReference(BNFlowGraphLayoutRequest* layout);
+ BINARYNINJACOREAPI void BNFreeFlowGraphLayoutRequest(BNFlowGraphLayoutRequest* layout);
+ BINARYNINJACOREAPI bool BNIsFlowGraphLayoutRequestComplete(BNFlowGraphLayoutRequest* layout);
+ BINARYNINJACOREAPI BNFlowGraph* BNGetGraphForFlowGraphLayoutRequest(BNFlowGraphLayoutRequest* layout);
+ BINARYNINJACOREAPI void BNAbortFlowGraphLayoutRequest(BNFlowGraphLayoutRequest* graph);
+ BINARYNINJACOREAPI bool BNIsILFlowGraph(BNFlowGraph* graph);
+ BINARYNINJACOREAPI bool BNIsLowLevelILFlowGraph(BNFlowGraph* graph);
+ BINARYNINJACOREAPI bool BNIsMediumLevelILFlowGraph(BNFlowGraph* graph);
+ BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFlowGraphLowLevelILFunction(BNFlowGraph* graph);
+ BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetFlowGraphMediumLevelILFunction(BNFlowGraph* graph);
+ BINARYNINJACOREAPI void BNSetFlowGraphLowLevelILFunction(BNFlowGraph* graph, BNLowLevelILFunction* func);
+ BINARYNINJACOREAPI void BNSetFlowGraphMediumLevelILFunction(BNFlowGraph* graph, BNMediumLevelILFunction* func);
- BINARYNINJACOREAPI void BNStartFunctionGraphLayout(BNFunctionGraph* graph, BNFunctionGraphType type);
- BINARYNINJACOREAPI bool BNIsFunctionGraphLayoutComplete(BNFunctionGraph* graph);
- BINARYNINJACOREAPI void BNSetFunctionGraphCompleteCallback(BNFunctionGraph* graph, void* ctxt, void (*func)(void* ctxt));
- BINARYNINJACOREAPI void BNAbortFunctionGraph(BNFunctionGraph* graph);
- BINARYNINJACOREAPI BNFunctionGraphType BNGetFunctionGraphType(BNFunctionGraph* graph);
- BINARYNINJACOREAPI bool BNIsILFunctionGraph(BNFunctionGraph* graph);
- BINARYNINJACOREAPI bool BNIsLowLevelILFunctionGraph(BNFunctionGraph* graph);
- BINARYNINJACOREAPI bool BNIsMediumLevelILFunctionGraph(BNFunctionGraph* graph);
- BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFunctionGraphLowLevelILFunction(BNFunctionGraph* graph);
- BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetFunctionGraphMediumLevelILFunction(BNFunctionGraph* graph);
+ BINARYNINJACOREAPI BNFlowGraphNode** BNGetFlowGraphNodes(BNFlowGraph* graph, size_t* count);
+ BINARYNINJACOREAPI BNFlowGraphNode* BNGetFlowGraphNode(BNFlowGraph* graph, size_t i);
+ BINARYNINJACOREAPI BNFlowGraphNode** BNGetFlowGraphNodesInRegion(
+ BNFlowGraph* graph, int left, int top, int right, int bottom, size_t* count);
+ BINARYNINJACOREAPI void BNFreeFlowGraphNodeList(BNFlowGraphNode** nodes, size_t count);
+ BINARYNINJACOREAPI bool BNFlowGraphHasNodes(BNFlowGraph* graph);
+ BINARYNINJACOREAPI size_t BNAddFlowGraphNode(BNFlowGraph* graph, BNFlowGraphNode* node);
- BINARYNINJACOREAPI BNFunctionGraphBlock** BNGetFunctionGraphBlocks(BNFunctionGraph* graph, size_t* count);
- BINARYNINJACOREAPI BNFunctionGraphBlock** BNGetFunctionGraphBlocksInRegion(
- BNFunctionGraph* graph, int left, int top, int right, int bottom, size_t* count);
- BINARYNINJACOREAPI void BNFreeFunctionGraphBlockList(BNFunctionGraphBlock** blocks, size_t count);
- BINARYNINJACOREAPI bool BNFunctionGraphHasBlocks(BNFunctionGraph* graph);
+ BINARYNINJACOREAPI int BNGetFlowGraphWidth(BNFlowGraph* graph);
+ BINARYNINJACOREAPI int BNGetFlowGraphHeight(BNFlowGraph* graph);
- BINARYNINJACOREAPI int BNGetFunctionGraphWidth(BNFunctionGraph* graph);
- BINARYNINJACOREAPI int BNGetFunctionGraphHeight(BNFunctionGraph* graph);
+ BINARYNINJACOREAPI BNFlowGraphNode* BNCreateFlowGraphNode(BNFlowGraph* graph);
+ BINARYNINJACOREAPI BNFlowGraphNode* BNNewFlowGraphNodeReference(BNFlowGraphNode* node);
+ BINARYNINJACOREAPI void BNFreeFlowGraphNode(BNFlowGraphNode* node);
- BINARYNINJACOREAPI bool BNIsFunctionGraphOptionSet(BNFunctionGraph* graph, BNDisassemblyOption option);
- BINARYNINJACOREAPI void BNSetFunctionGraphOption(BNFunctionGraph* graph, BNDisassemblyOption option, bool state);
+ BINARYNINJACOREAPI BNBasicBlock* BNGetFlowGraphBasicBlock(BNFlowGraphNode* node);
+ BINARYNINJACOREAPI void BNSetFlowGraphBasicBlock(BNFlowGraphNode* node, BNBasicBlock* block);
+ BINARYNINJACOREAPI int BNGetFlowGraphNodeX(BNFlowGraphNode* node);
+ BINARYNINJACOREAPI int BNGetFlowGraphNodeY(BNFlowGraphNode* node);
+ BINARYNINJACOREAPI int BNGetFlowGraphNodeWidth(BNFlowGraphNode* node);
+ BINARYNINJACOREAPI int BNGetFlowGraphNodeHeight(BNFlowGraphNode* node);
- BINARYNINJACOREAPI BNFunctionGraphBlock* BNNewFunctionGraphBlockReference(BNFunctionGraphBlock* block);
- BINARYNINJACOREAPI void BNFreeFunctionGraphBlock(BNFunctionGraphBlock* block);
+ BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetFlowGraphNodeLines(BNFlowGraphNode* node, size_t* count);
+ BINARYNINJACOREAPI void BNSetFlowGraphNodeLines(BNFlowGraphNode* node, BNDisassemblyTextLine* lines, size_t count);
+ BINARYNINJACOREAPI BNFlowGraphEdge* BNGetFlowGraphNodeOutgoingEdges(BNFlowGraphNode* node, size_t* count);
+ BINARYNINJACOREAPI void BNFreeFlowGraphNodeOutgoingEdgeList(BNFlowGraphEdge* edges, size_t count);
+ BINARYNINJACOREAPI void BNAddFlowGraphNodeOutgoingEdge(BNFlowGraphNode* node, BNBranchType type, BNFlowGraphNode* target);
- BINARYNINJACOREAPI BNBasicBlock* BNGetFunctionGraphBasicBlock(BNFunctionGraphBlock* block);
- BINARYNINJACOREAPI BNArchitecture* BNGetFunctionGraphBlockArchitecture(BNFunctionGraphBlock* block);
- BINARYNINJACOREAPI uint64_t BNGetFunctionGraphBlockStart(BNFunctionGraphBlock* block);
- BINARYNINJACOREAPI uint64_t BNGetFunctionGraphBlockEnd(BNFunctionGraphBlock* block);
- BINARYNINJACOREAPI int BNGetFunctionGraphBlockX(BNFunctionGraphBlock* block);
- BINARYNINJACOREAPI int BNGetFunctionGraphBlockY(BNFunctionGraphBlock* block);
- BINARYNINJACOREAPI int BNGetFunctionGraphBlockWidth(BNFunctionGraphBlock* block);
- BINARYNINJACOREAPI int BNGetFunctionGraphBlockHeight(BNFunctionGraphBlock* block);
+ BINARYNINJACOREAPI BNHighlightColor BNGetFlowGraphNodeHighlight(BNFlowGraphNode* node);
+ BINARYNINJACOREAPI void BNSetFlowGraphNodeHighlight(BNFlowGraphNode* node, BNHighlightColor color);
- BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetFunctionGraphBlockLines(BNFunctionGraphBlock* block, size_t* count);
- BINARYNINJACOREAPI BNFunctionGraphEdge* BNGetFunctionGraphBlockOutgoingEdges(BNFunctionGraphBlock* block, size_t* count);
- BINARYNINJACOREAPI void BNFreeFunctionGraphBlockOutgoingEdgeList(BNFunctionGraphEdge* edges, size_t count);
+ BINARYNINJACOREAPI void BNFinishPrepareForLayout(BNFlowGraph* graph);
+
+ BINARYNINJACOREAPI BNFlowGraph* BNUpdateFlowGraph(BNFlowGraph* graph);
// Symbols
BINARYNINJACOREAPI BNSymbol* BNCreateSymbol(BNSymbolType type, const char* shortName, const char* fullName,
@@ -3073,7 +3124,7 @@ extern "C"
BINARYNINJACOREAPI BNType* BNCreateArrayType(BNTypeWithConfidence* type, uint64_t elem);
BINARYNINJACOREAPI BNType* BNCreateFunctionType(BNTypeWithConfidence* returnValue,
BNCallingConventionWithConfidence* callingConvention, BNFunctionParameter* params,
- size_t paramCount, BNBoolWithConfidence* varArg, BNSizeWithConfidence* stackAdjust);
+ size_t paramCount, BNBoolWithConfidence* varArg, BNOffsetWithConfidence* stackAdjust);
BINARYNINJACOREAPI BNType* BNNewTypeReference(BNType* type);
BINARYNINJACOREAPI BNType* BNDuplicateType(BNType* type);
BINARYNINJACOREAPI char* BNGetTypeAndName(BNType* type, BNQualifiedName* name);
@@ -3106,7 +3157,7 @@ extern "C"
BINARYNINJACOREAPI void BNTypeSetMemberAccess(BNType* type, BNMemberAccessWithConfidence* access);
BINARYNINJACOREAPI void BNTypeSetConst(BNType* type, BNBoolWithConfidence* cnst);
BINARYNINJACOREAPI void BNTypeSetVolatile(BNType* type, BNBoolWithConfidence* vltl);
- BINARYNINJACOREAPI BNSizeWithConfidence BNGetTypeStackAdjustment(BNType* type);
+ BINARYNINJACOREAPI BNOffsetWithConfidence BNGetTypeStackAdjustment(BNType* type);
BINARYNINJACOREAPI char* BNGetTypeString(BNType* type, BNPlatform* platform);
BINARYNINJACOREAPI char* BNGetTypeStringBeforeName(BNType* type, BNPlatform* platform);
@@ -3449,6 +3500,8 @@ extern "C"
const char* plaintext);
BINARYNINJACOREAPI void BNShowHTMLReport(BNBinaryView* view, const char* title, const char* contents,
const char* plaintext);
+ BINARYNINJACOREAPI void BNShowGraphReport(BNBinaryView* view, const char* title, BNFlowGraph* graph);
+ BINARYNINJACOREAPI void BNShowReportCollection(const char* title, BNReportCollection* reports);
BINARYNINJACOREAPI bool BNGetTextLineInput(char** result, const char* prompt, const char* title);
BINARYNINJACOREAPI bool BNGetIntegerInput(int64_t* result, const char* prompt, const char* title);
BINARYNINJACOREAPI bool BNGetAddressInput(uint64_t* result, const char* prompt, const char* title,
@@ -3464,6 +3517,25 @@ extern "C"
BINARYNINJACOREAPI BNMessageBoxButtonResult BNShowMessageBox(const char* title, const char* text,
BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon);
+ BINARYNINJACOREAPI BNReportCollection* BNCreateReportCollection(void);
+ BINARYNINJACOREAPI BNReportCollection* BNNewReportCollectionReference(BNReportCollection* reports);
+ BINARYNINJACOREAPI void BNFreeReportCollection(BNReportCollection* reports);
+ BINARYNINJACOREAPI size_t BNGetReportCollectionCount(BNReportCollection* reports);
+ BINARYNINJACOREAPI BNReportType BNGetReportType(BNReportCollection* reports, size_t i);
+ BINARYNINJACOREAPI BNBinaryView* BNGetReportView(BNReportCollection* reports, size_t i);
+ BINARYNINJACOREAPI char* BNGetReportTitle(BNReportCollection* reports, size_t i);
+ BINARYNINJACOREAPI char* BNGetReportContents(BNReportCollection* reports, size_t i);
+ BINARYNINJACOREAPI char* BNGetReportPlainText(BNReportCollection* reports, size_t i);
+ BINARYNINJACOREAPI BNFlowGraph* BNGetReportFlowGraph(BNReportCollection* reports, size_t i);
+ BINARYNINJACOREAPI void BNAddPlainTextReportToCollection(BNReportCollection* reports, BNBinaryView* view,
+ const char* title, const char* contents);
+ BINARYNINJACOREAPI void BNAddMarkdownReportToCollection(BNReportCollection* reports, BNBinaryView* view,
+ const char* title, const char* contents, const char* plaintext);
+ BINARYNINJACOREAPI void BNAddHTMLReportToCollection(BNReportCollection* reports, BNBinaryView* view,
+ const char* title, const char* contents, const char* plaintext);
+ BINARYNINJACOREAPI void BNAddGraphReportToCollection(BNReportCollection* reports, BNBinaryView* view,
+ const char* title, BNFlowGraph* graph);
+
BINARYNINJACOREAPI bool BNDemangleGNU3(BNArchitecture* arch,
const char* mangledName,
BNType** outType,
diff --git a/binaryview.cpp b/binaryview.cpp
index a678d23b..e9e8b377 100644
--- a/binaryview.cpp
+++ b/binaryview.cpp
@@ -1739,6 +1739,7 @@ vector<LinearDisassemblyLine> BinaryView::GetPreviousLinearDisassemblyLines(Line
line.lineOffset = lines[i].lineOffset;
line.contents.addr = lines[i].contents.addr;
line.contents.instrIndex = lines[i].contents.instrIndex;
+ line.contents.highlight = lines[i].contents.highlight;
line.contents.tokens.reserve(lines[i].contents.count);
for (size_t j = 0; j < lines[i].contents.count; j++)
{
@@ -1788,6 +1789,7 @@ vector<LinearDisassemblyLine> BinaryView::GetNextLinearDisassemblyLines(LinearDi
line.lineOffset = lines[i].lineOffset;
line.contents.addr = lines[i].contents.addr;
line.contents.instrIndex = lines[i].contents.instrIndex;
+ line.contents.highlight = lines[i].contents.highlight;
line.contents.tokens.reserve(lines[i].contents.count);
for (size_t j = 0; j < lines[i].contents.count; j++)
{
@@ -1980,6 +1982,12 @@ void BinaryView::ShowHTMLReport(const string& title, const string& contents, con
}
+void BinaryView::ShowGraphReport(const string& title, FlowGraph* graph)
+{
+ BNShowGraphReport(m_object, title.c_str(), graph->GetObject());
+}
+
+
bool BinaryView::GetAddressInput(uint64_t& result, const string& prompt, const string& title)
{
uint64_t currentAddress = 0;
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 5148b9d5..59695147 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -15,11 +15,11 @@ Binaries are installed in the following locations by default:
- Linux: Wherever you extract it! (No standard location)
!!! Warning "Warning"
- Do not put any user content in the install-path of Binary Ninja. The auto-update process of Binary Ninja may replace any files included in these folders.
+ Do not put any user content in the install-path of Binary Ninja. The auto-update process of Binary Ninja may replace any files included in these folders.
### User Folder
-The base locations of user folders are:
+The base locations of user folders are:
- OS X: `~/Library/Application Support/Binary Ninja`
- Linux: `~/.binaryninja`
@@ -277,7 +277,15 @@ Settings are stored in the _user_ directory in the file `settings.json`. Each to
| pdb | auto-download-pdb | boolean | True | Automatically download pdb files from specified symbol servers |
| pdb | symbol-server-list | list(string) | ["http://msdl.microsoft.com/download/symbols"] | List of servers to query for pdb symbols. |
| python | interpreter | string | "python27.{dylib,dll,so.1}" | Python interpreter to load if one is not already present when plugins are loaded |
-
+| arch | x86.disassemblyFlavor | string | "BN_INTEL" | "BN_INTEL", "INTEL", or "AT&T" |
+| arch | x86.disassemblySeperator | string | ", " | What to put between operands in disassembly tokens |
+| arch | x86.disassemblyLowercase | bool | True | Lowercase opcodes, operands, and registers (False for uppercase) |
+ "arch" :
+ {
+ // "x86.disassemblyFlavor" : "AT&T",
+ // "x86.disassemblyFlavor" : "BN_INTEL",
+ "x86.disassemblyLowercase" : true,
+ "x86.disassemblySeperator" : ", "
Below is an example `settings.json` setting various options:
```
{
diff --git a/flowgraph.cpp b/flowgraph.cpp
new file mode 100644
index 00000000..dc7e628e
--- /dev/null
+++ b/flowgraph.cpp
@@ -0,0 +1,358 @@
+// Copyright (c) 2015-2017 Vector 35 LLC
+//
+// 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;
+
+
+FlowGraphLayoutRequest::FlowGraphLayoutRequest(FlowGraph* graph, const std::function<void()>& completeFunc):
+ m_completeFunc(completeFunc)
+{
+ m_object = BNStartFlowGraphLayout(graph->GetObject(), this, CompleteCallback);
+}
+
+
+FlowGraphLayoutRequest::~FlowGraphLayoutRequest()
+{
+ // This object is going away, so ensure that any pending completion routines are
+ // no longer called
+ Abort();
+
+ BNFreeFlowGraphLayoutRequest(m_object);
+}
+
+
+void FlowGraphLayoutRequest::CompleteCallback(void* ctxt)
+{
+ FlowGraphLayoutRequest* layout = (FlowGraphLayoutRequest*)ctxt;
+ layout->m_completeFunc();
+}
+
+
+Ref<FlowGraph> FlowGraphLayoutRequest::GetGraph() const
+{
+ return new CoreFlowGraph(BNGetGraphForFlowGraphLayoutRequest(m_object));
+}
+
+
+bool FlowGraphLayoutRequest::IsComplete() const
+{
+ return BNIsFlowGraphLayoutRequestComplete(m_object);
+}
+
+
+void FlowGraphLayoutRequest::Abort()
+{
+ // Must clear the callback with the core before clearing our own function object, as until it
+ // is cleared in the core it can be called at any time from a different thread.
+ BNAbortFlowGraphLayoutRequest(m_object);
+ m_completeFunc = []() {};
+}
+
+
+FlowGraph::FlowGraph()
+{
+ BNCustomFlowGraph callbacks;
+ callbacks.context = this;
+ callbacks.prepareForLayout = PrepareForLayoutCallback;
+ callbacks.populateNodes = PopulateNodesCallback;
+ callbacks.completeLayout = CompleteLayoutCallback;
+ m_object = BNCreateCustomFlowGraph(&callbacks);
+}
+
+
+FlowGraph::FlowGraph(BNFlowGraph* graph)
+{
+ m_object = graph;
+}
+
+
+void FlowGraph::PrepareForLayoutCallback(void* ctxt)
+{
+ FlowGraph* graph = (FlowGraph*)ctxt;
+ graph->PrepareForLayout();
+}
+
+
+void FlowGraph::PopulateNodesCallback(void* ctxt)
+{
+ FlowGraph* graph = (FlowGraph*)ctxt;
+ graph->PopulateNodes();
+}
+
+
+void FlowGraph::CompleteLayoutCallback(void* ctxt)
+{
+ FlowGraph* graph = (FlowGraph*)ctxt;
+ graph->CompleteLayout();
+}
+
+
+BNFlowGraph* FlowGraph::UpdateCallback(void* ctxt)
+{
+ FlowGraph* graph = (FlowGraph*)ctxt;
+ Ref<FlowGraph> result = graph->Update();
+ if (!result)
+ return nullptr;
+ return BNNewFlowGraphReference(result->GetObject());
+}
+
+
+void FlowGraph::FinishPrepareForLayout()
+{
+ BNFinishPrepareForLayout(m_object);
+}
+
+
+void FlowGraph::PrepareForLayout()
+{
+ FinishPrepareForLayout();
+}
+
+
+void FlowGraph::PopulateNodes()
+{
+}
+
+
+void FlowGraph::CompleteLayout()
+{
+}
+
+
+Ref<Function> FlowGraph::GetFunction() const
+{
+ BNFunction* func = BNGetFunctionForFlowGraph(m_object);
+ if (!func)
+ return nullptr;
+ return new Function(BNNewFunctionReference(func));
+}
+
+
+void FlowGraph::SetFunction(Function* func)
+{
+ BNSetFunctionForFlowGraph(m_object, func ? func->GetObject() : nullptr);
+}
+
+
+int FlowGraph::GetHorizontalNodeMargin() const
+{
+ return BNGetHorizontalFlowGraphNodeMargin(m_object);
+}
+
+
+int FlowGraph::GetVerticalNodeMargin() const
+{
+ return BNGetVerticalFlowGraphNodeMargin(m_object);
+}
+
+
+void FlowGraph::SetNodeMargins(int horiz, int vert)
+{
+ BNSetFlowGraphNodeMargins(m_object, horiz, vert);
+}
+
+
+Ref<FlowGraphLayoutRequest> FlowGraph::StartLayout(const std::function<void()>& func)
+{
+ return new FlowGraphLayoutRequest(this, func);
+}
+
+
+bool FlowGraph::IsLayoutComplete()
+{
+ return BNIsFlowGraphLayoutComplete(m_object);
+}
+
+
+vector<Ref<FlowGraphNode>> FlowGraph::GetNodes()
+{
+ size_t count;
+ BNFlowGraphNode** nodes = BNGetFlowGraphNodes(m_object, &count);
+
+ vector<Ref<FlowGraphNode>> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ {
+ auto node = m_cachedNodes.find(nodes[i]);
+ if (node == m_cachedNodes.end())
+ {
+ FlowGraphNode* newNode = new FlowGraphNode(BNNewFlowGraphNodeReference(nodes[i]));
+ m_cachedNodes[nodes[i]] = newNode;
+ result.push_back(newNode);
+ }
+ else
+ {
+ result.push_back(node->second);
+ }
+ }
+
+ BNFreeFlowGraphNodeList(nodes, count);
+ return result;
+}
+
+
+Ref<FlowGraphNode> FlowGraph::GetNode(size_t i)
+{
+ BNFlowGraphNode* node = BNGetFlowGraphNode(m_object, i);
+ if (!node)
+ return nullptr;
+
+ auto nodeIter = m_cachedNodes.find(node);
+ if (nodeIter == m_cachedNodes.end())
+ {
+ FlowGraphNode* newNode = new FlowGraphNode(node);
+ m_cachedNodes[node] = newNode;
+ return newNode;
+ }
+ else
+ {
+ BNFreeFlowGraphNode(node);
+ return nodeIter->second;
+ }
+}
+
+
+bool FlowGraph::HasNodes() const
+{
+ return BNFlowGraphHasNodes(m_object);
+}
+
+
+size_t FlowGraph::AddNode(FlowGraphNode* node)
+{
+ m_cachedNodes[node->GetObject()] = node;
+ return BNAddFlowGraphNode(m_object, node->GetObject());
+}
+
+
+int FlowGraph::GetWidth() const
+{
+ return BNGetFlowGraphWidth(m_object);
+}
+
+
+int FlowGraph::GetHeight() const
+{
+ return BNGetFlowGraphHeight(m_object);
+}
+
+
+vector<Ref<FlowGraphNode>> FlowGraph::GetNodesInRegion(int left, int top, int right, int bottom)
+{
+ size_t count;
+ BNFlowGraphNode** nodes = BNGetFlowGraphNodesInRegion(m_object, left, top, right, bottom, &count);
+
+ vector<Ref<FlowGraphNode>> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ {
+ auto node = m_cachedNodes.find(nodes[i]);
+ if (node == m_cachedNodes.end())
+ {
+ FlowGraphNode* newNode = new FlowGraphNode(BNNewFlowGraphNodeReference(nodes[i]));
+ m_cachedNodes[nodes[i]] = newNode;
+ result.push_back(newNode);
+ }
+ else
+ {
+ result.push_back(node->second);
+ }
+ }
+
+ BNFreeFlowGraphNodeList(nodes, count);
+ return result;
+}
+
+
+bool FlowGraph::IsILGraph() const
+{
+ return BNIsILFlowGraph(m_object);
+}
+
+
+bool FlowGraph::IsLowLevelILGraph() const
+{
+ return BNIsLowLevelILFlowGraph(m_object);
+}
+
+
+bool FlowGraph::IsMediumLevelILGraph() const
+{
+ return BNIsMediumLevelILFlowGraph(m_object);
+}
+
+
+Ref<LowLevelILFunction> FlowGraph::GetLowLevelILFunction() const
+{
+ BNLowLevelILFunction* func = BNGetFlowGraphLowLevelILFunction(m_object);
+ if (!func)
+ return nullptr;
+ return new LowLevelILFunction(func);
+}
+
+
+Ref<MediumLevelILFunction> FlowGraph::GetMediumLevelILFunction() const
+{
+ BNMediumLevelILFunction* func = BNGetFlowGraphMediumLevelILFunction(m_object);
+ if (!func)
+ return nullptr;
+ return new MediumLevelILFunction(func);
+}
+
+
+void FlowGraph::SetLowLevelILFunction(LowLevelILFunction* func)
+{
+ BNSetFlowGraphLowLevelILFunction(m_object, func ? func->GetObject() : nullptr);
+}
+
+
+void FlowGraph::SetMediumLevelILFunction(MediumLevelILFunction* func)
+{
+ BNSetFlowGraphMediumLevelILFunction(m_object, func ? func->GetObject() : nullptr);
+}
+
+
+void FlowGraph::Show(const string& title)
+{
+ ShowGraphReport(title, this);
+}
+
+
+Ref<FlowGraph> FlowGraph::Update()
+{
+ return nullptr;
+}
+
+
+CoreFlowGraph::CoreFlowGraph(BNFlowGraph* graph): FlowGraph(graph)
+{
+}
+
+
+Ref<FlowGraph> CoreFlowGraph::Update()
+{
+ BNFlowGraph* graph = BNUpdateFlowGraph(GetObject());
+ if (!graph)
+ return nullptr;
+ return new CoreFlowGraph(graph);
+}
diff --git a/flowgraphnode.cpp b/flowgraphnode.cpp
new file mode 100644
index 00000000..60912df1
--- /dev/null
+++ b/flowgraphnode.cpp
@@ -0,0 +1,206 @@
+// Copyright (c) 2015-2017 Vector 35 LLC
+//
+// 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;
+
+
+FlowGraphNode::FlowGraphNode(FlowGraph* graph)
+{
+ m_object = BNCreateFlowGraphNode(graph->GetObject());
+ m_cachedLinesValid = false;
+ m_cachedEdgesValid = false;
+}
+
+
+FlowGraphNode::FlowGraphNode(BNFlowGraphNode* node)
+{
+ m_object = node;
+ m_cachedLinesValid = false;
+ m_cachedEdgesValid = false;
+}
+
+
+Ref<BasicBlock> FlowGraphNode::GetBasicBlock() const
+{
+ BNBasicBlock* block = BNGetFlowGraphBasicBlock(m_object);
+ if (!block)
+ return nullptr;
+ return new BasicBlock(block);
+}
+
+
+void FlowGraphNode::SetBasicBlock(BasicBlock* block)
+{
+ BNSetFlowGraphBasicBlock(m_object, block ? block->GetObject() : nullptr);
+}
+
+
+int FlowGraphNode::GetX() const
+{
+ return BNGetFlowGraphNodeX(m_object);
+}
+
+
+int FlowGraphNode::GetY() const
+{
+ return BNGetFlowGraphNodeY(m_object);
+}
+
+
+int FlowGraphNode::GetWidth() const
+{
+ return BNGetFlowGraphNodeWidth(m_object);
+}
+
+
+int FlowGraphNode::GetHeight() const
+{
+ return BNGetFlowGraphNodeHeight(m_object);
+}
+
+
+const vector<DisassemblyTextLine>& FlowGraphNode::GetLines()
+{
+ if (m_cachedLinesValid)
+ return m_cachedLines;
+
+ size_t count;
+ BNDisassemblyTextLine* lines = BNGetFlowGraphNodeLines(m_object, &count);
+
+ vector<DisassemblyTextLine> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ {
+ DisassemblyTextLine line;
+ line.addr = lines[i].addr;
+ line.instrIndex = lines[i].instrIndex;
+ line.highlight = lines[i].highlight;
+ line.tokens.reserve(lines[i].count);
+ for (size_t j = 0; j < lines[i].count; j++)
+ {
+ InstructionTextToken token;
+ token.type = lines[i].tokens[j].type;
+ token.text = lines[i].tokens[j].text;
+ token.value = lines[i].tokens[j].value;
+ token.size = lines[i].tokens[j].size;
+ token.operand = lines[i].tokens[j].operand;
+ token.context = lines[i].tokens[j].context;
+ token.confidence = lines[i].tokens[j].confidence;
+ token.address = lines[i].tokens[j].address;
+ line.tokens.push_back(token);
+ }
+ result.push_back(line);
+ }
+
+ BNFreeDisassemblyTextLines(lines, count);
+ m_cachedLines = result;
+ m_cachedLinesValid = true;
+ return m_cachedLines;
+}
+
+
+void FlowGraphNode::SetLines(const vector<DisassemblyTextLine>& lines)
+{
+ BNDisassemblyTextLine* buf = new BNDisassemblyTextLine[lines.size()];
+ for (size_t i = 0; i < lines.size(); i++)
+ {
+ const DisassemblyTextLine& line = lines[i];
+ buf[i].addr = line.addr;
+ buf[i].instrIndex = line.instrIndex;
+ buf[i].highlight = line.highlight;
+ buf[i].tokens = new BNInstructionTextToken[line.tokens.size()];
+ buf[i].count = line.tokens.size();
+ for (size_t j = 0; j < line.tokens.size(); j++)
+ {
+ const InstructionTextToken& token = line.tokens[j];
+ buf[i].tokens[j].type = token.type;
+ buf[i].tokens[j].text = BNAllocString(token.text.c_str());
+ buf[i].tokens[j].value = token.value;
+ buf[i].tokens[j].size = token.size;
+ buf[i].tokens[j].operand = token.operand;
+ buf[i].tokens[j].context = token.context;
+ buf[i].tokens[j].confidence = token.confidence;
+ buf[i].tokens[j].address = token.address;
+ }
+ }
+
+ BNSetFlowGraphNodeLines(m_object, buf, lines.size());
+
+ for (size_t i = 0; i < lines.size(); i++)
+ {
+ for (size_t j = 0; j < buf[i].count; j++)
+ BNFreeString(buf[i].tokens[j].text);
+ delete[] buf[i].tokens;
+ }
+ delete[] buf;
+
+ m_cachedLines = lines;
+ m_cachedLinesValid = true;
+}
+
+
+const vector<FlowGraphEdge>& FlowGraphNode::GetOutgoingEdges()
+{
+ if (m_cachedEdgesValid)
+ return m_cachedEdges;
+
+ size_t count;
+ BNFlowGraphEdge* edges = BNGetFlowGraphNodeOutgoingEdges(m_object, &count);
+
+ vector<FlowGraphEdge> result;
+ result.reserve(count);
+ for (size_t i = 0; i < count; i++)
+ {
+ FlowGraphEdge edge;
+ edge.type = edges[i].type;
+ edge.target = edges[i].target ? new FlowGraphNode(BNNewFlowGraphNodeReference(edges[i].target)) : nullptr;
+ edge.points.insert(edge.points.begin(), &edges[i].points[0], &edges[i].points[edges[i].pointCount]);
+ edge.backEdge = edges[i].backEdge;
+ result.push_back(edge);
+ }
+
+ BNFreeFlowGraphNodeOutgoingEdgeList(edges, count);
+ m_cachedEdges = result;
+ m_cachedEdgesValid = true;
+ return m_cachedEdges;
+}
+
+
+void FlowGraphNode::AddOutgoingEdge(BNBranchType type, FlowGraphNode* target)
+{
+ BNAddFlowGraphNodeOutgoingEdge(m_object, type, target->GetObject());
+ m_cachedEdges.clear();
+ m_cachedEdgesValid = false;
+}
+
+
+BNHighlightColor FlowGraphNode::GetHighlight() const
+{
+ return BNGetFlowGraphNodeHighlight(m_object);
+}
+
+
+void FlowGraphNode::SetHighlight(const BNHighlightColor& color)
+{
+ BNSetFlowGraphNodeHighlight(m_object, color);
+}
diff --git a/function.cpp b/function.cpp
index e441d1b5..e17166ff 100644
--- a/function.cpp
+++ b/function.cpp
@@ -120,6 +120,12 @@ Function::~Function()
}
+Ref<BinaryView> Function::GetView() const
+{
+ return new BinaryView(BNGetFunctionData(m_object));
+}
+
+
Ref<Platform> Function::GetPlatform() const
{
return new Platform(BNGetFunctionPlatform(m_object));
@@ -534,10 +540,10 @@ Confidence<bool> Function::HasVariableArguments() const
}
-Confidence<size_t> Function::GetStackAdjustment() const
+Confidence<int64_t> Function::GetStackAdjustment() const
{
- BNSizeWithConfidence sc = BNGetFunctionStackAdjustment(m_object);
- return Confidence<size_t>(sc.value, sc.confidence);
+ BNOffsetWithConfidence oc = BNGetFunctionStackAdjustment(m_object);
+ return Confidence<int64_t>(oc.value, oc.confidence);
}
@@ -639,12 +645,12 @@ void Function::SetAutoCanReturn(const Confidence<bool>& returns)
}
-void Function::SetAutoStackAdjustment(const Confidence<size_t>& stackAdjust)
+void Function::SetAutoStackAdjustment(const Confidence<int64_t>& stackAdjust)
{
- BNSizeWithConfidence sc;
- sc.value = stackAdjust.GetValue();
- sc.confidence = stackAdjust.GetConfidence();
- BNSetAutoFunctionStackAdjustment(m_object, &sc);
+ BNOffsetWithConfidence oc;
+ oc.value = stackAdjust.GetValue();
+ oc.confidence = stackAdjust.GetConfidence();
+ BNSetAutoFunctionStackAdjustment(m_object, &oc);
}
@@ -753,12 +759,12 @@ void Function::SetCanReturn(const Confidence<bool>& returns)
}
-void Function::SetStackAdjustment(const Confidence<size_t>& stackAdjust)
+void Function::SetStackAdjustment(const Confidence<int64_t>& stackAdjust)
{
- BNSizeWithConfidence sc;
- sc.value = stackAdjust.GetValue();
- sc.confidence = stackAdjust.GetConfidence();
- BNSetUserFunctionStackAdjustment(m_object, &sc);
+ BNOffsetWithConfidence oc;
+ oc.value = stackAdjust.GetValue();
+ oc.confidence = stackAdjust.GetConfidence();
+ BNSetUserFunctionStackAdjustment(m_object, &oc);
}
@@ -804,10 +810,10 @@ void Function::ApplyAutoDiscoveredType(Type* type)
}
-Ref<FunctionGraph> Function::CreateFunctionGraph()
+Ref<FlowGraph> Function::CreateFunctionGraph(BNFunctionGraphType type, DisassemblySettings* settings)
{
- BNFunctionGraph* graph = BNCreateFunctionGraph(m_object);
- return new FunctionGraph(graph);
+ BNFlowGraph* graph = BNCreateFunctionGraph(m_object, type, settings ? settings->GetObject() : nullptr);
+ return new CoreFlowGraph(graph);
}
@@ -1022,7 +1028,7 @@ vector<IndirectBranchInfo> Function::GetIndirectBranchesAt(Architecture* arch, u
}
-void Function::SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<size_t>& adjust)
+void Function::SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<int64_t>& adjust)
{
BNSetAutoCallStackAdjustment(m_object, arch->GetObject(), addr, adjust.GetValue(), adjust.GetConfidence());
}
@@ -1053,7 +1059,7 @@ void Function::SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t a
}
-void Function::SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<size_t>& adjust)
+void Function::SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence<int64_t>& adjust)
{
BNSetUserCallStackAdjustment(m_object, arch->GetObject(), addr, adjust.GetValue(), adjust.GetConfidence());
}
@@ -1084,10 +1090,10 @@ void Function::SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t a
}
-Confidence<size_t> Function::GetCallStackAdjustment(Architecture* arch, uint64_t addr)
+Confidence<int64_t> Function::GetCallStackAdjustment(Architecture* arch, uint64_t addr)
{
- BNSizeWithConfidence result = BNGetCallStackAdjustment(m_object, arch->GetObject(), addr);
- return Confidence<size_t>(result.value, result.confidence);
+ BNOffsetWithConfidence result = BNGetCallStackAdjustment(m_object, arch->GetObject(), addr);
+ return Confidence<int64_t>(result.value, result.confidence);
}
@@ -1112,6 +1118,12 @@ Confidence<int32_t> Function::GetCallRegisterStackAdjustment(Architecture* arch,
}
+bool Function::IsCallInstruction(Architecture* arch, uint64_t addr)
+{
+ return BNIsCallInstruction(m_object, arch->GetObject(), addr);
+}
+
+
vector<vector<InstructionTextToken>> Function::GetBlockAnnotations(Architecture* arch, uint64_t addr)
{
size_t count;
@@ -1340,6 +1352,7 @@ vector<DisassemblyTextLine> Function::GetTypeTokens(DisassemblySettings* setting
DisassemblyTextLine line;
line.addr = lines[i].addr;
line.instrIndex = lines[i].instrIndex;
+ line.highlight = lines[i].highlight;
line.tokens.reserve(lines[i].count);
for (size_t j = 0; j < lines[i].count; j++)
{
@@ -1392,6 +1405,21 @@ void Function::SetAnalysisSkipOverride(BNFunctionAnalysisSkipOverride skip)
}
+Ref<FlowGraph> Function::GetUnresolvedStackAdjustmentGraph()
+{
+ BNFlowGraph* graph = BNGetUnresolvedStackAdjustmentGraph(m_object);
+ if (!graph)
+ return nullptr;
+ return new CoreFlowGraph(graph);
+}
+
+
+void Function::RequestDebugReport(const string& name)
+{
+ BNRequestFunctionDebugReport(m_object, name.c_str());
+}
+
+
AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(Function* func): m_func(func)
{
if (m_func)
diff --git a/functiongraph.cpp b/functiongraph.cpp
deleted file mode 100644
index 9948d70e..00000000
--- a/functiongraph.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright (c) 2015-2017 Vector 35 LLC
-//
-// 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;
-
-
-FunctionGraph::FunctionGraph(BNFunctionGraph* graph): m_graph(graph)
-{
-}
-
-
-FunctionGraph::~FunctionGraph()
-{
- // This object is going away, so ensure that any pending completion routines are
- // no longer called
- Abort();
-
- BNFreeFunctionGraph(m_graph);
-}
-
-
-void FunctionGraph::CompleteCallback(void* ctxt)
-{
- FunctionGraph* graph = (FunctionGraph*)ctxt;
- graph->m_completeFunc();
-}
-
-
-Ref<Function> FunctionGraph::GetFunction() const
-{
- return new Function(BNNewFunctionReference(BNGetFunctionForFunctionGraph(m_graph)));
-}
-
-
-int FunctionGraph::GetHorizontalBlockMargin() const
-{
- return BNGetHorizontalFunctionGraphBlockMargin(m_graph);
-}
-
-
-int FunctionGraph::GetVerticalBlockMargin() const
-{
- return BNGetVerticalFunctionGraphBlockMargin(m_graph);
-}
-
-
-void FunctionGraph::SetBlockMargins(int horiz, int vert)
-{
- BNSetFunctionGraphBlockMargins(m_graph, horiz, vert);
-}
-
-
-Ref<DisassemblySettings> FunctionGraph::GetSettings()
-{
- return new DisassemblySettings(BNGetFunctionGraphSettings(m_graph));
-}
-
-
-void FunctionGraph::StartLayout(BNFunctionGraphType type)
-{
- BNStartFunctionGraphLayout(m_graph, type);
-}
-
-
-bool FunctionGraph::IsLayoutComplete()
-{
- return BNIsFunctionGraphLayoutComplete(m_graph);
-}
-
-
-void FunctionGraph::OnComplete(const std::function<void()>& func)
-{
- m_completeFunc = func;
- BNSetFunctionGraphCompleteCallback(m_graph, this, CompleteCallback);
-}
-
-
-void FunctionGraph::Abort()
-{
- // Must clear the callback with the core before clearing our own function object, as until it
- // is cleared in the core it can be called at any time from a different thread.
- BNAbortFunctionGraph(m_graph);
- m_completeFunc = []() {};
-}
-
-
-vector<Ref<FunctionGraphBlock>> FunctionGraph::GetBlocks()
-{
- size_t count;
- BNFunctionGraphBlock** blocks = BNGetFunctionGraphBlocks(m_graph, &count);
-
- vector<Ref<FunctionGraphBlock>> result;
- result.reserve(count);
- for (size_t i = 0; i < count; i++)
- {
- auto block = m_cachedBlocks.find(blocks[i]);
- if (block == m_cachedBlocks.end())
- {
- FunctionGraphBlock* newBlock = new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i]));
- m_cachedBlocks[blocks[i]] = newBlock;
- result.push_back(newBlock);
- }
- else
- {
- result.push_back(block->second);
- }
- }
-
- BNFreeFunctionGraphBlockList(blocks, count);
- return result;
-}
-
-
-bool FunctionGraph::HasBlocks() const
-{
- return BNFunctionGraphHasBlocks(m_graph);
-}
-
-
-int FunctionGraph::GetWidth() const
-{
- return BNGetFunctionGraphWidth(m_graph);
-}
-
-
-int FunctionGraph::GetHeight() const
-{
- return BNGetFunctionGraphHeight(m_graph);
-}
-
-
-vector<Ref<FunctionGraphBlock>> FunctionGraph::GetBlocksInRegion(int left, int top, int right, int bottom)
-{
- size_t count;
- BNFunctionGraphBlock** blocks = BNGetFunctionGraphBlocksInRegion(m_graph, left, top, right, bottom, &count);
-
- vector<Ref<FunctionGraphBlock>> result;
- result.reserve(count);
- for (size_t i = 0; i < count; i++)
- {
- auto block = m_cachedBlocks.find(blocks[i]);
- if (block == m_cachedBlocks.end())
- {
- FunctionGraphBlock* newBlock = new FunctionGraphBlock(BNNewFunctionGraphBlockReference(blocks[i]));
- m_cachedBlocks[blocks[i]] = newBlock;
- result.push_back(newBlock);
- }
- else
- {
- result.push_back(block->second);
- }
- }
-
- BNFreeFunctionGraphBlockList(blocks, count);
- return result;
-}
-
-
-bool FunctionGraph::IsOptionSet(BNDisassemblyOption option) const
-{
- return BNIsFunctionGraphOptionSet(m_graph, option);
-}
-
-
-void FunctionGraph::SetOption(BNDisassemblyOption option, bool state)
-{
- BNSetFunctionGraphOption(m_graph, option, state);
-}
-
-
-bool FunctionGraph::IsILGraph() const
-{
- return BNIsILFunctionGraph(m_graph);
-}
-
-
-bool FunctionGraph::IsLowLevelILGraph() const
-{
- return BNIsLowLevelILFunctionGraph(m_graph);
-}
-
-
-bool FunctionGraph::IsMediumLevelILGraph() const
-{
- return BNIsMediumLevelILFunctionGraph(m_graph);
-}
-
-
-Ref<LowLevelILFunction> FunctionGraph::GetLowLevelILFunction() const
-{
- BNLowLevelILFunction* func = BNGetFunctionGraphLowLevelILFunction(m_graph);
- if (!func)
- return nullptr;
- return new LowLevelILFunction(func);
-}
-
-
-Ref<MediumLevelILFunction> FunctionGraph::GetMediumLevelILFunction() const
-{
- BNMediumLevelILFunction* func = BNGetFunctionGraphMediumLevelILFunction(m_graph);
- if (!func)
- return nullptr;
- return new MediumLevelILFunction(func);
-}
diff --git a/functiongraphblock.cpp b/functiongraphblock.cpp
deleted file mode 100644
index 469fb175..00000000
--- a/functiongraphblock.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (c) 2015-2017 Vector 35 LLC
-//
-// 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;
-
-
-FunctionGraphBlock::FunctionGraphBlock(BNFunctionGraphBlock* block)
-{
- m_object = block;
- m_cachedLinesValid = false;
- m_cachedEdgesValid = false;
-}
-
-
-Ref<BasicBlock> FunctionGraphBlock::GetBasicBlock() const
-{
- return new BasicBlock(BNGetFunctionGraphBasicBlock(m_object));
-}
-
-
-Ref<Architecture> FunctionGraphBlock::GetArchitecture() const
-{
- return new CoreArchitecture(BNGetFunctionGraphBlockArchitecture(m_object));
-}
-
-
-uint64_t FunctionGraphBlock::GetStart() const
-{
- return BNGetFunctionGraphBlockStart(m_object);
-}
-
-
-uint64_t FunctionGraphBlock::GetEnd() const
-{
- return BNGetFunctionGraphBlockEnd(m_object);
-}
-
-
-int FunctionGraphBlock::GetX() const
-{
- return BNGetFunctionGraphBlockX(m_object);
-}
-
-
-int FunctionGraphBlock::GetY() const
-{
- return BNGetFunctionGraphBlockY(m_object);
-}
-
-
-int FunctionGraphBlock::GetWidth() const
-{
- return BNGetFunctionGraphBlockWidth(m_object);
-}
-
-
-int FunctionGraphBlock::GetHeight() const
-{
- return BNGetFunctionGraphBlockHeight(m_object);
-}
-
-
-const vector<DisassemblyTextLine>& FunctionGraphBlock::GetLines()
-{
- if (m_cachedLinesValid)
- return m_cachedLines;
-
- size_t count;
- BNDisassemblyTextLine* lines = BNGetFunctionGraphBlockLines(m_object, &count);
-
- vector<DisassemblyTextLine> result;
- result.reserve(count);
- for (size_t i = 0; i < count; i++)
- {
- DisassemblyTextLine line;
- line.addr = lines[i].addr;
- line.instrIndex = lines[i].instrIndex;
- line.tokens.reserve(lines[i].count);
- for (size_t j = 0; j < lines[i].count; j++)
- {
- InstructionTextToken token;
- token.type = lines[i].tokens[j].type;
- token.text = lines[i].tokens[j].text;
- token.value = lines[i].tokens[j].value;
- token.size = lines[i].tokens[j].size;
- token.operand = lines[i].tokens[j].operand;
- token.context = lines[i].tokens[j].context;
- token.confidence = lines[i].tokens[j].confidence;
- token.address = lines[i].tokens[j].address;
- line.tokens.push_back(token);
- }
- result.push_back(line);
- }
-
- BNFreeDisassemblyTextLines(lines, count);
- m_cachedLines = result;
- m_cachedLinesValid = true;
- return m_cachedLines;
-}
-
-
-const vector<FunctionGraphEdge>& FunctionGraphBlock::GetOutgoingEdges()
-{
- if (m_cachedEdgesValid)
- return m_cachedEdges;
-
- size_t count;
- BNFunctionGraphEdge* edges = BNGetFunctionGraphBlockOutgoingEdges(m_object, &count);
-
- vector<FunctionGraphEdge> result;
- result.reserve(count);
- for (size_t i = 0; i < count; i++)
- {
- FunctionGraphEdge edge;
- edge.type = edges[i].type;
- edge.target = edges[i].target ? new BasicBlock(BNNewBasicBlockReference(edges[i].target)) : nullptr;
- edge.points.insert(edge.points.begin(), &edges[i].points[0], &edges[i].points[edges[i].pointCount]);
- edge.backEdge = edges[i].backEdge;
- result.push_back(edge);
- }
-
- BNFreeFunctionGraphBlockOutgoingEdgeList(edges, count);
- m_cachedEdges = result;
- m_cachedEdgesValid = true;
- return m_cachedEdges;
-}
diff --git a/interaction.cpp b/interaction.cpp
index 2f84c4ec..5650f629 100644
--- a/interaction.cpp
+++ b/interaction.cpp
@@ -117,6 +117,16 @@ void InteractionHandler::ShowHTMLReport(Ref<BinaryView> view, const string& titl
}
+void InteractionHandler::ShowGraphReport(Ref<BinaryView>, const std::string&, Ref<FlowGraph>)
+{
+}
+
+
+void InteractionHandler::ShowReportCollection(const string&, Ref<ReportCollection>)
+{
+}
+
+
bool InteractionHandler::GetIntegerInput(int64_t& result, const string& prompt, const string& title)
{
while (true)
@@ -194,6 +204,21 @@ static void ShowHTMLReportCallback(void* ctxt, BNBinaryView* view, const char* t
}
+static void ShowGraphReportCallback(void* ctxt, BNBinaryView* view, const char* title, BNFlowGraph* graph)
+{
+ InteractionHandler* handler = (InteractionHandler*)ctxt;
+ handler->ShowGraphReport(view ? new BinaryView(BNNewViewReference(view)) : nullptr, title,
+ new CoreFlowGraph(BNNewFlowGraphReference(graph)));
+}
+
+
+static void ShowReportCollectionCallback(void* ctxt, const char* title, BNReportCollection* reports)
+{
+ InteractionHandler* handler = (InteractionHandler*)ctxt;
+ handler->ShowReportCollection(title, new ReportCollection(BNNewReportCollectionReference(reports)));
+}
+
+
static bool GetTextLineInputCallback(void* ctxt, char** result, const char* prompt, const char* title)
{
InteractionHandler* handler = (InteractionHandler*)ctxt;
@@ -360,6 +385,8 @@ void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler)
cb.showPlainTextReport = ShowPlainTextReportCallback;
cb.showMarkdownReport = ShowMarkdownReportCallback;
cb.showHTMLReport = ShowHTMLReportCallback;
+ cb.showGraphReport = ShowGraphReportCallback;
+ cb.showReportCollection = ShowReportCollectionCallback;
cb.getTextLineInput = GetTextLineInputCallback;
cb.getIntegerInput = GetIntegerInputCallback;
cb.getAddressInput = GetAddressInputCallback;
@@ -400,6 +427,22 @@ void BinaryNinja::ShowHTMLReport(const string& title, const string& contents, co
}
+void BinaryNinja::ShowGraphReport(const string& title, FlowGraph* graph)
+{
+ Ref<Function> func = graph->GetFunction();
+ if (func)
+ BNShowGraphReport(func->GetView()->GetObject(), title.c_str(), graph->GetObject());
+ else
+ BNShowGraphReport(nullptr, title.c_str(), graph->GetObject());
+}
+
+
+void BinaryNinja::ShowReportCollection(const string& title, ReportCollection* reports)
+{
+ BNShowReportCollection(title.c_str(), reports->GetObject());
+}
+
+
bool BinaryNinja::GetTextLineInput(string& result, const string& prompt, const string& title)
{
char* value = nullptr;
@@ -553,3 +596,100 @@ BNMessageBoxButtonResult BinaryNinja::ShowMessageBox(const string& title, const
{
return BNShowMessageBox(title.c_str(), text.c_str(), buttons, icon);
}
+
+
+ReportCollection::ReportCollection()
+{
+ m_object = BNCreateReportCollection();
+}
+
+
+ReportCollection::ReportCollection(BNReportCollection* reports)
+{
+ m_object = reports;
+}
+
+
+size_t ReportCollection::GetCount() const
+{
+ return BNGetReportCollectionCount(m_object);
+}
+
+
+BNReportType ReportCollection::GetType(size_t i) const
+{
+ return BNGetReportType(m_object, i);
+}
+
+
+Ref<BinaryView> ReportCollection::GetView(size_t i) const
+{
+ BNBinaryView* view = BNGetReportView(m_object, i);
+ if (!view)
+ return nullptr;
+ return new BinaryView(view);
+}
+
+
+string ReportCollection::GetTitle(size_t i) const
+{
+ char* str = BNGetReportTitle(m_object, i);
+ string result = str;
+ BNFreeString(str);
+ return result;
+}
+
+
+string ReportCollection::GetContents(size_t i) const
+{
+ char* str = BNGetReportContents(m_object, i);
+ string result = str;
+ BNFreeString(str);
+ return result;
+}
+
+
+string ReportCollection::GetPlainText(size_t i) const
+{
+ char* str = BNGetReportPlainText(m_object, i);
+ string result = str;
+ BNFreeString(str);
+ return result;
+}
+
+
+Ref<FlowGraph> ReportCollection::GetFlowGraph(size_t i) const
+{
+ BNFlowGraph* graph = BNGetReportFlowGraph(m_object, i);
+ if (!graph)
+ return nullptr;
+ return new CoreFlowGraph(graph);
+}
+
+
+void ReportCollection::AddPlainTextReport(Ref<BinaryView> view, const string& title, const string& contents)
+{
+ BNAddPlainTextReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), contents.c_str());
+}
+
+
+void ReportCollection::AddMarkdownReport(Ref<BinaryView> view, const string& title, const string& contents,
+ const string& plainText)
+{
+ BNAddMarkdownReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), contents.c_str(),
+ plainText.c_str());
+}
+
+
+void ReportCollection::AddHTMLReport(Ref<BinaryView> view, const string& title, const string& contents,
+ const string& plainText)
+{
+ BNAddHTMLReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), contents.c_str(),
+ plainText.c_str());
+}
+
+
+void ReportCollection::AddGraphReport(Ref<BinaryView> view, const string& title, Ref<FlowGraph> graph)
+{
+ BNAddGraphReportToCollection(m_object, view ? view->GetObject() : nullptr, title.c_str(), graph->GetObject());
+}
diff --git a/lowlevelil.cpp b/lowlevelil.cpp
index 40748327..3e09e085 100644
--- a/lowlevelil.cpp
+++ b/lowlevelil.cpp
@@ -766,3 +766,10 @@ size_t LowLevelILFunction::GetMappedMediumLevelILExprIndex(size_t expr) const
{
return BNGetMappedMediumLevelILExprIndex(m_object, expr);
}
+
+
+Ref<FlowGraph> LowLevelILFunction::CreateFunctionGraph(DisassemblySettings* settings)
+{
+ BNFlowGraph* graph = BNCreateLowLevelILFunctionGraph(m_object, settings ? settings->GetObject() : nullptr);
+ return new CoreFlowGraph(graph);
+}
diff --git a/lowlevelilinstruction.cpp b/lowlevelilinstruction.cpp
index 1522596b..f185b274 100644
--- a/lowlevelilinstruction.cpp
+++ b/lowlevelilinstruction.cpp
@@ -2510,11 +2510,11 @@ int64_t LowLevelILInstruction::GetVector() const
}
-size_t LowLevelILInstruction::GetStackAdjustment() const
+int64_t LowLevelILInstruction::GetStackAdjustment() const
{
size_t operandIndex;
if (GetOperandIndexForUsage(StackAdjustmentLowLevelOperandUsage, operandIndex))
- return (size_t)GetRawOperandAsInteger(operandIndex);
+ return GetRawOperandAsInteger(operandIndex);
throw LowLevelILInstructionAccessException();
}
@@ -3181,7 +3181,7 @@ ExprId LowLevelILFunction::Call(ExprId dest, const ILSourceLocation& loc)
}
-ExprId LowLevelILFunction::CallStackAdjust(ExprId dest, size_t adjust,
+ExprId LowLevelILFunction::CallStackAdjust(ExprId dest, int64_t adjust,
const std::map<uint32_t, int32_t>& regStackAdjust, const ILSourceLocation& loc)
{
vector<size_t> list;
diff --git a/lowlevelilinstruction.h b/lowlevelilinstruction.h
index 09cae9f4..4a54b8c5 100644
--- a/lowlevelilinstruction.h
+++ b/lowlevelilinstruction.h
@@ -714,7 +714,7 @@ namespace BinaryNinja
template <BNLowLevelILOperation N> int64_t GetConstant() const { return As<N>().GetConstant(); }
template <BNLowLevelILOperation N> uint64_t GetOffset() const { return As<N>().GetOffset(); }
template <BNLowLevelILOperation N> int64_t GetVector() const { return As<N>().GetVector(); }
- template <BNLowLevelILOperation N> size_t GetStackAdjustment() const { return As<N>().GetStackAdjustment(); }
+ template <BNLowLevelILOperation N> int64_t GetStackAdjustment() const { return As<N>().GetStackAdjustment(); }
template <BNLowLevelILOperation N> size_t GetTarget() const { return As<N>().GetTarget(); }
template <BNLowLevelILOperation N> size_t GetTrueTarget() const { return As<N>().GetTrueTarget(); }
template <BNLowLevelILOperation N> size_t GetFalseTarget() const { return As<N>().GetFalseTarget(); }
@@ -779,7 +779,7 @@ namespace BinaryNinja
int64_t GetConstant() const;
uint64_t GetOffset() const;
int64_t GetVector() const;
- size_t GetStackAdjustment() const;
+ int64_t GetStackAdjustment() const;
size_t GetTarget() const;
size_t GetTrueTarget() const;
size_t GetFalseTarget() const;
@@ -1112,7 +1112,7 @@ namespace BinaryNinja
template <> struct LowLevelILInstructionAccessor<LLIL_CALL_STACK_ADJUST>: public LowLevelILInstructionBase
{
LowLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); }
- size_t GetStackAdjustment() const { return (size_t)GetRawOperandAsInteger(1); }
+ int64_t GetStackAdjustment() const { return GetRawOperandAsInteger(1); }
std::map<uint32_t, int32_t> GetRegisterStackAdjustments() const { return GetRawOperandAsRegisterStackAdjustments(2); }
};
template <> struct LowLevelILInstructionAccessor<LLIL_TAILCALL>: public LowLevelILInstructionBase
diff --git a/mediumlevelil.cpp b/mediumlevelil.cpp
index cac45dd6..2d1fe904 100644
--- a/mediumlevelil.cpp
+++ b/mediumlevelil.cpp
@@ -738,3 +738,10 @@ Confidence<Ref<Type>> MediumLevelILFunction::GetExprType(const MediumLevelILInst
{
return GetExprType(expr.exprIndex);
}
+
+
+Ref<FlowGraph> MediumLevelILFunction::CreateFunctionGraph(DisassemblySettings* settings)
+{
+ BNFlowGraph* graph = BNCreateMediumLevelILFunctionGraph(m_object, settings ? settings->GetObject() : nullptr);
+ return new CoreFlowGraph(graph);
+}
diff --git a/mediumlevelilinstruction.cpp b/mediumlevelilinstruction.cpp
index c7627bd7..08472004 100644
--- a/mediumlevelilinstruction.cpp
+++ b/mediumlevelilinstruction.cpp
@@ -122,6 +122,7 @@ unordered_map<BNMediumLevelILOperation, vector<MediumLevelILOperandUsage>>
{MLIL_ADDRESS_OF_FIELD, {SourceVariableMediumLevelOperandUsage, OffsetMediumLevelOperandUsage}},
{MLIL_JUMP, {DestExprMediumLevelOperandUsage}},
{MLIL_JUMP_TO, {DestExprMediumLevelOperandUsage, TargetListMediumLevelOperandUsage}},
+ {MLIL_RET_HINT, {DestExprMediumLevelOperandUsage}},
{MLIL_CALL, {OutputVariablesMediumLevelOperandUsage, DestExprMediumLevelOperandUsage,
ParameterExprsMediumLevelOperandUsage}},
{MLIL_CALL_UNTYPED, {OutputVariablesSubExprMediumLevelOperandUsage, DestExprMediumLevelOperandUsage,
@@ -1323,6 +1324,7 @@ void MediumLevelILInstruction::VisitExprs(const std::function<bool(const MediumL
case MLIL_BOOL_TO_INT:
case MLIL_JUMP:
case MLIL_JUMP_TO:
+ case MLIL_RET_HINT:
case MLIL_IF:
case MLIL_UNIMPL_MEM:
case MLIL_LOAD:
@@ -1592,6 +1594,7 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
case MLIL_LOW_PART:
case MLIL_BOOL_TO_INT:
case MLIL_JUMP:
+ case MLIL_RET_HINT:
case MLIL_UNIMPL_MEM:
case MLIL_FSQRT:
case MLIL_FNEG:
@@ -2506,6 +2509,12 @@ ExprId MediumLevelILFunction::JumpTo(ExprId dest, const vector<BNMediumLevelILLa
}
+ExprId MediumLevelILFunction::ReturnHint(ExprId dest, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_RET_HINT, loc, 0, dest);
+}
+
+
ExprId MediumLevelILFunction::Call(const vector<Variable>& output, ExprId dest,
const vector<ExprId>& params, const ILSourceLocation& loc)
{
diff --git a/mediumlevelilinstruction.h b/mediumlevelilinstruction.h
index ec8a8371..9f4784a1 100644
--- a/mediumlevelilinstruction.h
+++ b/mediumlevelilinstruction.h
@@ -814,6 +814,10 @@ namespace BinaryNinja
MediumLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); }
MediumLevelILIndexList GetTargetList() const { return GetRawOperandAsIndexList(1); }
};
+ template <> struct MediumLevelILInstructionAccessor<MLIL_RET_HINT>: public MediumLevelILInstructionBase
+ {
+ MediumLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); }
+ };
template <> struct MediumLevelILInstructionAccessor<MLIL_CALL>: public MediumLevelILInstructionBase
{
diff --git a/python/__init__.py b/python/__init__.py
index 947739ca..9f8cbc79 100644
--- a/python/__init__.py
+++ b/python/__init__.py
@@ -96,6 +96,7 @@ import binaryninja._binaryninjacore as core
# "pluginmanager",
# "setting",
# "metadata",
+# "flowgraph",
# ]
from binaryninja.enums import *
from binaryninja.databuffer import *
@@ -126,6 +127,7 @@ from binaryninja.downloadprovider import *
from binaryninja.pluginmanager import *
from binaryninja.setting import *
from binaryninja.metadata import *
+from binaryninja.flowgraph import *
def shutdown():
diff --git a/python/basicblock.py b/python/basicblock.py
index 11d5a7f4..353771d9 100644
--- a/python/basicblock.py
+++ b/python/basicblock.py
@@ -245,14 +245,7 @@ class BasicBlock(object):
>>> current_basic_block.highlight
<color: blue>
"""
- color = core.BNGetBasicBlockHighlight(self.handle)
- if color.style == HighlightColorStyle.StandardHighlightColor:
- return highlight.HighlightColor(color=color.color, alpha=color.alpha)
- elif color.style == HighlightColorStyle.MixedHighlightColor:
- return highlight.HighlightColor(color=color.color, mix_color=color.mixColor, mix=color.mix, alpha=color.alpha)
- elif color.style == HighlightColorStyle.CustomHighlightColor:
- return highlight.HighlightColor(red=color.r, green=color.g, blue=color.b, alpha=color.alpha)
- return highlight.HighlightColor(color=HighlightStandardColor.NoHighlightColor)
+ return highlight.HighlightColor._from_core_struct(core.BNGetBasicBlockHighlight(self.handle))
@highlight.setter
def highlight(self, value):
@@ -345,6 +338,7 @@ class BasicBlock(object):
il_instr = self.il_function[lines[i].instrIndex]
else:
il_instr = None
+ color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
tokens = []
for j in range(0, lines[i].count):
token_type = InstructionTextTokenType(lines[i].tokens[j].type)
@@ -356,7 +350,7 @@ class BasicBlock(object):
confidence = lines[i].tokens[j].confidence
address = lines[i].tokens[j].address
tokens.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
- result.append(binaryninja.function.DisassemblyTextLine(addr, tokens, il_instr))
+ result.append(binaryninja.function.DisassemblyTextLine(tokens, addr, il_instr, color))
core.BNFreeDisassemblyTextLines(lines, count.value)
return result
diff --git a/python/binaryview.py b/python/binaryview.py
index 8d44872b..f7ead7a6 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -36,6 +36,7 @@ from binaryninja import databuffer
from binaryninja import basicblock
from binaryninja import lineardisassembly
from binaryninja import metadata
+from binaryninja import highlight
# 2-3 compatibility
from binaryninja import range
@@ -3147,6 +3148,7 @@ class BinaryView(object):
func = binaryninja.function.Function(self, core.BNNewFunctionReference(lines[i].function))
if lines[i].block:
block = basicblock.BasicBlock(self, core.BNNewBasicBlockReference(lines[i].block))
+ color = highlight.HighlightColor._from_core_struct(lines[i].contents.highlight)
addr = lines[i].contents.addr
tokens = []
for j in range(0, lines[i].contents.count):
@@ -3159,7 +3161,7 @@ class BinaryView(object):
confidence = lines[i].contents.tokens[j].confidence
address = lines[i].contents.tokens[j].address
tokens.append(binaryninja.function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
- contents = binaryninja.function.DisassemblyTextLine(addr, tokens)
+ contents = binaryninja.function.DisassemblyTextLine(tokens, addr, color = color)
result.append(lineardisassembly.LinearDisassemblyLine(lines[i].type, func, block, lines[i].lineOffset, contents))
func = None
@@ -3538,6 +3540,9 @@ class BinaryView(object):
def show_html_report(self, title, contents, plaintext = ""):
core.BNShowHTMLReport(self.handle, title, contents, plaintext)
+ def show_graph_report(self, title, graph):
+ core.BNShowHTMLReport(self.handle, title, graph.handle)
+
def get_address_input(self, prompt, title, current_address = None):
if current_address is None:
current_address = self.file.offset
diff --git a/python/flowgraph.py b/python/flowgraph.py
new file mode 100644
index 00000000..4d551c83
--- /dev/null
+++ b/python/flowgraph.py
@@ -0,0 +1,633 @@
+# Copyright (c) 2018 Vector 35 LLC
+#
+# 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 threading
+import traceback
+
+# Binary Ninja components
+import binaryninja
+from binaryninja.enums import (BranchType, InstructionTextTokenType, HighlightStandardColor)
+from binaryninja import _binaryninjacore as core
+from binaryninja import function
+from binaryninja import binaryview
+from binaryninja import lowlevelil
+from binaryninja import mediumlevelil
+from binaryninja import basicblock
+from binaryninja import log
+from binaryninja import highlight
+
+# 2-3 compatibility
+from binaryninja import range
+
+
+class FlowGraphEdge(object):
+ def __init__(self, branch_type, source, target, points, back_edge):
+ self.type = BranchType(branch_type)
+ self.source = source
+ self.target = target
+ self.points = points
+ self.back_edge = back_edge
+
+ def __repr__(self):
+ return "<%s: %s>" % (self.type.name, repr(self.target))
+
+
+class FlowGraphNode(object):
+ def __init__(self, graph, handle = None):
+ if handle is None:
+ handle = core.BNCreateFlowGraphNode(graph.handle)
+ self.handle = handle
+ self.graph = graph
+
+ def __del__(self):
+ core.BNFreeFlowGraphNode(self.handle)
+
+ def __eq__(self, value):
+ if not isinstance(value, FlowGraphNode):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, FlowGraphNode):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
+ @property
+ def basic_block(self):
+ """Basic block associated with this part of the flow graph (read-only)"""
+ block = core.BNGetFlowGraphBasicBlock(self.handle)
+ if not block:
+ return None
+ func_handle = core.BNGetBasicBlockFunction(block)
+ if not func_handle:
+ core.BNFreeBasicBlock(block)
+ return None
+
+ view = binaryview.BinaryView(handle = core.BNGetFunctionData(func_handle))
+ func = function.Function(view, func_handle)
+
+ if core.BNIsLowLevelILBasicBlock(block):
+ block = lowlevelil.LowLevelILBasicBlock(view, block,
+ lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func))
+ elif core.BNIsMediumLevelILBasicBlock(block):
+ block = mediumlevelil.MediumLevelILBasicBlock(view, block,
+ mediumlevelil.MediumLevelILFunction(func.arch, core.BNGetBasicBlockMediumLevelILFunction(block), func))
+ else:
+ block = basicblock.BasicBlock(view, block)
+ return block
+
+ @property
+ def x(self):
+ """Flow graph block X (read-only)"""
+ return core.BNGetFlowGraphNodeX(self.handle)
+
+ @property
+ def y(self):
+ """Flow graph block Y (read-only)"""
+ return core.BNGetFlowGraphNodeY(self.handle)
+
+ @property
+ def width(self):
+ """Flow graph block width (read-only)"""
+ return core.BNGetFlowGraphNodeWidth(self.handle)
+
+ @property
+ def height(self):
+ """Flow graph block height (read-only)"""
+ return core.BNGetFlowGraphNodeHeight(self.handle)
+
+ @property
+ def lines(self):
+ """Flow graph block list of text lines"""
+ count = ctypes.c_ulonglong()
+ lines = core.BNGetFlowGraphNodeLines(self.handle, count)
+ block = self.basic_block
+ result = []
+ for i in range(0, count.value):
+ addr = lines[i].addr
+ if (lines[i].instrIndex != 0xffffffffffffffff) and (block is not None) and hasattr(block, 'il_function'):
+ il_instr = block.il_function[lines[i].instrIndex]
+ else:
+ il_instr = None
+ color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
+ tokens = []
+ for j in range(0, lines[i].count):
+ token_type = InstructionTextTokenType(lines[i].tokens[j].type)
+ text = lines[i].tokens[j].text
+ value = lines[i].tokens[j].value
+ size = lines[i].tokens[j].size
+ operand = lines[i].tokens[j].operand
+ context = lines[i].tokens[j].context
+ confidence = lines[i].tokens[j].confidence
+ address = lines[i].tokens[j].address
+ tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+ result.append(function.DisassemblyTextLine(tokens, addr, il_instr, color))
+ core.BNFreeDisassemblyTextLines(lines, count.value)
+ return result
+
+ @lines.setter
+ def lines(self, lines):
+ if isinstance(lines, str):
+ lines = lines.split('\n')
+ line_buf = (core.BNDisassemblyTextLine * len(lines))()
+ for i in range(0, len(lines)):
+ line = lines[i]
+ if isinstance(line, str):
+ line = function.DisassemblyTextLine([function.InstructionTextToken(InstructionTextTokenType.TextToken, line)])
+ if not isinstance(line, function.DisassemblyTextLine):
+ line = function.DisassemblyTextLine(line)
+ 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
+ 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._get_core_struct()
+ line_buf[i].count = len(line.tokens)
+ line_buf[i].tokens = (core.BNInstructionTextToken * len(line.tokens))()
+ for j in range(0, len(line.tokens)):
+ line_buf[i].tokens[j].type = line.tokens[j].type
+ line_buf[i].tokens[j].text = line.tokens[j].text
+ line_buf[i].tokens[j].value = line.tokens[j].value
+ line_buf[i].tokens[j].size = line.tokens[j].size
+ line_buf[i].tokens[j].operand = line.tokens[j].operand
+ line_buf[i].tokens[j].context = line.tokens[j].context
+ line_buf[i].tokens[j].confidence = line.tokens[j].confidence
+ line_buf[i].tokens[j].address = line.tokens[j].address
+ core.BNSetFlowGraphNodeLines(self.handle, line_buf, len(lines))
+
+ @property
+ def outgoing_edges(self):
+ """Flow graph block list of outgoing edges (read-only)"""
+ count = ctypes.c_ulonglong()
+ edges = core.BNGetFlowGraphNodeOutgoingEdges(self.handle, count)
+ result = []
+ for i in range(0, count.value):
+ branch_type = BranchType(edges[i].type)
+ target = edges[i].target
+ if target:
+ target = FlowGraphNode(self.graph, core.BNNewFlowGraphNodeReference(target))
+ points = []
+ for j in range(0, edges[i].pointCount):
+ points.append((edges[i].points[j].x, edges[i].points[j].y))
+ result.append(FlowGraphEdge(branch_type, self, target, points, edges[i].backEdge))
+ core.BNFreeFlowGraphNodeOutgoingEdgeList(edges, count.value)
+ return result
+
+ @property
+ def highlight(self):
+ """Gets or sets the highlight color for the node
+
+ :Example:
+ >>> g = FlowGraph()
+ >>> node = FlowGraphNode(g)
+ >>> node.highlight = HighlightStandardColor.BlueHighlightColor
+ >>> node.highlight
+ <color: blue>
+ """
+ return highlight.HighlightColor._from_core_struct(core.BNGetFlowGraphNodeHighlight(self.handle))
+
+ @highlight.setter
+ def highlight(self, color):
+ 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)
+ core.BNSetFlowGraphNodeHighlight(self.handle, color._get_core_struct())
+
+ def __repr__(self):
+ block = self.basic_block
+ if block:
+ arch = block.arch
+ if arch:
+ return "<graph node: %s@%#x-%#x>" % (arch.name, block.start, block.end)
+ else:
+ return "<graph node: %#x-%#x>" % (block.start, block.end)
+ return "<graph node>"
+
+ def __iter__(self):
+ count = ctypes.c_ulonglong()
+ lines = core.BNGetFlowGraphNodeLines(self.handle, count)
+ block = self.basic_block
+ try:
+ for i in range(0, count.value):
+ addr = lines[i].addr
+ if (lines[i].instrIndex != 0xffffffffffffffff) and (block is not None) and hasattr(block, 'il_function'):
+ il_instr = block.il_function[lines[i].instrIndex]
+ else:
+ il_instr = None
+ tokens = []
+ for j in range(0, lines[i].count):
+ token_type = InstructionTextTokenType(lines[i].tokens[j].type)
+ text = lines[i].tokens[j].text
+ value = lines[i].tokens[j].value
+ size = lines[i].tokens[j].size
+ operand = lines[i].tokens[j].operand
+ context = lines[i].tokens[j].context
+ confidence = lines[i].tokens[j].confidence
+ address = lines[i].tokens[j].address
+ tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
+ yield function.DisassemblyTextLine(tokens, addr, il_instr)
+ finally:
+ core.BNFreeDisassemblyTextLines(lines, count.value)
+
+ def add_outgoing_edge(self, edge_type, target):
+ """
+ ``add_outgoing_edge`` connects two flow graph nodes with an edge.
+
+ :param BranchType edge_type: Type of edge to add
+ :param FlowGraphNode target: Target node object
+ """
+ core.BNAddFlowGraphNodeOutgoingEdge(self.handle, edge_type, target.handle)
+
+
+class FlowGraphLayoutRequest(object):
+ def __init__(self, graph, callback = None):
+ self.on_complete = callback
+ self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._complete)
+ self.handle = core.BNStartFlowGraphLayout(graph.handle, None, self._cb)
+
+ def __del__(self):
+ self.abort()
+ core.BNFreeFlowGraphLayoutRequest(self.handle)
+
+ def _complete(self, ctxt):
+ try:
+ if self.on_complete is not None:
+ self.on_complete()
+ except:
+ log.log_error(traceback.format_exc())
+
+ @property
+ def complete(self):
+ """Whether flow graph layout is complete (read-only)"""
+ return core.BNIsFlowGraphLayoutRequestComplete(self.handle)
+
+ @property
+ def graph(self):
+ """Flow graph that is being processed (read-only)"""
+ return CoreFlowGraph(core.BNGetGraphForFlowGraphLayoutRequest(self.handle))
+
+ def abort(self):
+ core.BNAbortFlowGraphLayoutRequest(self.handle)
+ self.on_complete = None
+
+
+class FlowGraph(object):
+ """
+ ``class FlowGraph`` implements a directed flow graph to be shown in the UI. This class allows plugins to
+ create custom flow graphs and render them in the UI using the flow graph report API.
+
+ An example of creating a flow graph and presenting it in the UI:
+
+ >>> graph = FlowGraph()
+ >>> node_a = FlowGraphNode(graph)
+ >>> node_a.lines = ["Node A"]
+ >>> node_b = FlowGraphNode(graph)
+ >>> node_b.lines = ["Node B"]
+ >>> node_c = FlowGraphNode(graph)
+ >>> node_c.lines = ["Node C"]
+ >>> graph.append(node_a)
+ 0
+ >>> graph.append(node_b)
+ 1
+ >>> graph.append(node_c)
+ 2
+ >>> node_a.add_outgoing_edge(BranchType.UnconditionalBranch, node_b)
+ >>> node_a.add_outgoing_edge(BranchType.UnconditionalBranch, node_c)
+ >>> show_graph_report("Custom Graph", graph)
+
+ .. note:: In the current implementation, only graphs that have a single start node where all other nodes are \
+ reachable from outgoing edges can be rendered correctly. This describes the natural limitations of a control \
+ flow graph, which is what the rendering logic was designed for. Graphs that have nodes that are only reachable \
+ from incoming edges, or graphs that have disjoint subgraphs will not render correctly. This will be fixed \
+ in a future version.
+ """
+ def __init__(self, handle = None):
+ if handle is None:
+ self._ext_cb = core.BNCustomFlowGraph()
+ self._ext_cb.context = 0
+ self._ext_cb.prepareForLayout = self._ext_cb.prepareForLayout.__class__(self._prepare_for_layout)
+ self._ext_cb.populateNodes = self._ext_cb.populateNodes.__class__(self._populate_nodes)
+ self._ext_cb.completeLayout = self._ext_cb.completeLayout.__class__(self._complete_layout)
+ self._ext_cb.update = self._ext_cb.update.__class__(self._update)
+ handle = core.BNCreateCustomFlowGraph(self._ext_cb)
+ self.handle = handle
+
+ def __del__(self):
+ core.BNFreeFlowGraph(self.handle)
+
+ def __eq__(self, value):
+ if not isinstance(value, FlowGraph):
+ return False
+ return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
+
+ def __ne__(self, value):
+ if not isinstance(value, FlowGraph):
+ return True
+ return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
+
+ def _prepare_for_layout(self, ctxt):
+ try:
+ self.prepare_for_layout()
+ except:
+ log.log_error(traceback.format_exc())
+
+ def _populate_nodes(self, ctxt):
+ try:
+ self.populate_nodes()
+ except:
+ log.log_error(traceback.format_exc())
+
+ def _complete_layout(self, ctxt):
+ try:
+ self.complete_layout()
+ except:
+ log.log_error(traceback.format_exc())
+
+ def _update(self, ctxt):
+ try:
+ graph = self.update()
+ if graph is None:
+ return None
+ return core.BNNewFlowGraphReference(graph.handle)
+ except:
+ log.log_error(traceback.format_exc())
+ return None
+
+ def finish_prepare_for_layout(self):
+ """
+ ``finish_prepare_for_layout`` signals that preparations for rendering a graph are complete.
+ This method should only be called by a ``prepare_for_layout`` reimplementation.
+ """
+ core.BNFinishPrepareForLayout(self.handle)
+
+ def prepare_for_layout(self):
+ """
+ ``prepare_for_layout`` can be overridden by subclasses to handling preparations that must take
+ place before a flow graph is rendered, such as waiting for a function to finish analysis. If
+ this function is overridden, the ``finish_prepare_for_layout`` method must be called once
+ preparations are completed.
+ """
+ self.finish_prepare_for_layout()
+
+ def populate_nodes(self):
+ """
+ ``prepare_for_layout`` can be overridden by subclasses to create nodes in a graph when a flow
+ graph needs to be rendered. This will happen on a worker thread and will not block the UI.
+ """
+ pass
+
+ def complete_layout(self):
+ """
+ ``complete_layout`` can be overridden by subclasses and is called when a graph layout is completed.
+ """
+ pass
+
+ @property
+ def function(self):
+ """Function for a flow graph"""
+ func = core.BNGetFunctionForFlowGraph(self.handle)
+ if func is None:
+ return None
+ return function.Function(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), func)
+
+ @function.setter
+ def function(self, func):
+ if func is not None:
+ func = func.handle
+ core.BNSetFunctionForFlowGraph(self.handle, func)
+
+ @property
+ def complete(self):
+ """Whether flow graph layout is complete (read-only)"""
+ return core.BNIsFlowGraphLayoutComplete(self.handle)
+
+ @property
+ def nodes(self):
+ """List of nodes in graph (read-only)"""
+ count = ctypes.c_ulonglong()
+ blocks = core.BNGetFlowGraphNodes(self.handle, count)
+ result = []
+ for i in range(0, count.value):
+ result.append(FlowGraphNode(self, core.BNNewFlowGraphNodeReference(blocks[i])))
+ core.BNFreeFlowGraphNodeList(blocks, count.value)
+ return result
+
+ @property
+ def has_nodes(self):
+ """Whether the flow graph has at least one node (read-only)"""
+ return core.BNFlowGraphHasNodes(self.handle)
+
+ @property
+ def width(self):
+ """Flow graph width (read-only)"""
+ return core.BNGetFlowGraphWidth(self.handle)
+
+ @property
+ def height(self):
+ """Flow graph height (read-only)"""
+ return core.BNGetFlowGraphHeight(self.handle)
+
+ @property
+ def horizontal_block_margin(self):
+ return core.BNGetHorizontalFlowGraphBlockMargin(self.handle)
+
+ @horizontal_block_margin.setter
+ def horizontal_block_margin(self, value):
+ core.BNSetFlowGraphBlockMargins(self.handle, value, self.vertical_block_margin)
+
+ @property
+ def vertical_block_margin(self):
+ return core.BNGetVerticalFlowGraphBlockMargin(self.handle)
+
+ @vertical_block_margin.setter
+ def vertical_block_margin(self, value):
+ core.BNSetFlowGraphBlockMargins(self.handle, self.horizontal_block_margin, value)
+
+ @property
+ def is_il(self):
+ return core.BNIsILFlowGraph(self.handle)
+
+ @property
+ def is_low_level_il(self):
+ return core.BNIsLowLevelILFlowGraph(self.handle)
+
+ @property
+ def is_medium_level_il(self):
+ return core.BNIsMediumLevelILFlowGraph(self.handle)
+
+ @property
+ def il_function(self):
+ if self.is_low_level_il:
+ il_func = core.BNGetFlowGraphLowLevelILFunction(self.handle)
+ if not il_func:
+ return None
+ function = self.function
+ if function is None:
+ return None
+ return lowlevelil.LowLevelILFunction(function.arch, il_func, function)
+ if self.is_medium_level_il:
+ il_func = core.BNGetFlowGraphMediumLevelILFunction(self.handle)
+ if not il_func:
+ return None
+ function = self.function
+ if function is None:
+ return None
+ return mediumlevelil.MediumLevelILFunction(function.arch, il_func, function)
+ return None
+
+ @il_function.setter
+ def il_function(self, func):
+ if isinstance(func, lowlevelil.LowLevelILFunction):
+ core.BNSetFlowGraphLowLevelILFunction(self.handle, func.handle)
+ core.BNSetFlowGraphMediumLevelILFunction(self.handle, None)
+ elif isinstance(func, mediumlevelil.MediumLevelILFunction):
+ core.BNSetFlowGraphLowLevelILFunction(self.handle, None)
+ core.BNSetFlowGraphMediumLevelILFunction(self.handle, func.handle)
+ elif func is None:
+ core.BNSetFlowGraphLowLevelILFunction(self.handle, None)
+ core.BNSetFlowGraphMediumLevelILFunction(self.handle, None)
+ else:
+ raise TypeError("expected IL function for setting il_function property")
+
+ def __setattr__(self, name, value):
+ try:
+ object.__setattr__(self, name, value)
+ except AttributeError:
+ raise AttributeError("attribute '%s' is read only" % name)
+
+ def __repr__(self):
+ function = self.function
+ if function is None:
+ return "<flow graph>"
+ return "<graph of %s>" % repr(function)
+
+ def __iter__(self):
+ count = ctypes.c_ulonglong()
+ nodes = core.BNGetFlowGraphNodes(self.handle, count)
+ try:
+ for i in range(0, count.value):
+ yield FlowGraphNode(self, core.BNNewFlowGraphNodeReference(nodes[i]))
+ finally:
+ core.BNFreeFlowGraphNodeList(nodes, count.value)
+
+ def layout(self, callback = None):
+ """
+ ``layout`` starts rendering a graph for display. Once a layout is complete, each node will contain
+ coordinates and extents that can be used to render a graph with minimum additional computation.
+ This function does not wait for the graph to be ready to display, but a callback can be provided
+ to signal when the graph is ready.
+
+ :param callable() callback: Function to be called when the graph is ready to display
+ :return: Pending flow graph layout request object
+ :rtype: FlowGraphLayoutRequest
+ """
+ return FlowGraphLayoutRequest(self, callback)
+
+ def _wait_complete(self):
+ self._wait_cond.acquire()
+ self._wait_cond.notify()
+ self._wait_cond.release()
+
+ def layout_and_wait(self):
+ """
+ ``layout_and_wait`` starts rendering a graph for display, and waits for the graph to be ready to
+ display. After this function returns, each node will contain coordinates and extents that can be
+ used to render a graph with minimum additional computation.
+
+ Do not use this API on the UI thread (use ``layout`` with a callback instead).
+ """
+ self._wait_cond = threading.Condition()
+ request = self.layout(self._wait_complete)
+
+ self._wait_cond.acquire()
+ while not request.complete:
+ self._wait_cond.wait()
+ self._wait_cond.release()
+
+ def get_nodes_in_region(self, left, top, right, bottom):
+ count = ctypes.c_ulonglong()
+ nodes = core.BNGetFlowGraphNodesInRegion(self.handle, left, top, right, bottom, count)
+ result = []
+ for i in range(0, count.value):
+ result.append(FlowGraphNode(self, core.BNNewFlowGraphNodeReference(nodes[i])))
+ core.BNFreeFlowGraphNodeList(nodes, count.value)
+ return result
+
+ def append(self, node):
+ """
+ ``append`` adds a node to a flow graph.
+
+ :param FlowGraphNode node: Node to add
+ :return: Index of node
+ :rtype: int
+ """
+ return core.BNAddFlowGraphNode(self.handle, node.handle)
+
+ def __getitem__(self, i):
+ node = core.BNGetFlowGraphNode(self.handle, i)
+ if node is None:
+ return None
+ return FlowGraphNode(self, node)
+
+ def show(self, title):
+ """
+ ``show`` displays the graph in a new tab in the UI.
+
+ :param str title: Title to show in the new tab
+ """
+ binaryninja.interaction.show_graph_report(title, self)
+
+ def update(self):
+ """
+ ``update`` can be overridden by subclasses to allow a graph to be updated after it has been
+ presented in the UI. This will automatically occur if the function referenced by the ``function``
+ property has been updated.
+
+ Return a new ``FlowGraph`` object with the new information if updates are desired. If the graph
+ does not need updating, ``None`` can be returned to leave the graph in its current state.
+
+ :return: Updated graph, or ``None``
+ :rtype: FlowGraph
+ """
+ return None
+
+
+class CoreFlowGraph(FlowGraph):
+ def __init__(self, handle):
+ super(CoreFlowGraph, self).__init__(handle)
+
+ def update(self):
+ graph = core.BNUpdateFlowGraph(self.handle)
+ if not graph:
+ return None
+ return CoreFlowGraph(graph)
diff --git a/python/function.py b/python/function.py
index 0589a5e2..6da86196 100644
--- a/python/function.py
+++ b/python/function.py
@@ -704,13 +704,13 @@ class Function(object):
@stack_adjustment.setter
def stack_adjustment(self, value):
- sc = core.BNSizeWithConfidence()
- sc.value = int(value)
+ oc = core.BNOffsetWithConfidence()
+ oc.value = int(value)
if hasattr(value, 'confidence'):
- sc.confidence = value.confidence
+ oc.confidence = value.confidence
else:
- sc.confidence = types.max_confidence
- core.BNSetUserFunctionStackAdjustment(self.handle, sc)
+ oc.confidence = types.max_confidence
+ core.BNSetUserFunctionStackAdjustment(self.handle, oc)
@property
def reg_stack_adjustments(self):
@@ -847,6 +847,14 @@ class Function(object):
def analysis_skip_override(self, override):
core.BNSetFunctionAnalysisSkipOverride(self.handle, override)
+ @property
+ def unresolved_stack_adjustment_graph(self):
+ """Flow graph of unresolved stack adjustments (read-only)"""
+ graph = core.BNGetUnresolvedStackAdjustmentGraph(self.handle)
+ if not graph:
+ return None
+ return binaryninja.flowgraph.CoreFlowGraph(graph)
+
def __iter__(self):
count = ctypes.c_ulonglong()
blocks = core.BNGetFunctionBasicBlockList(self.handle, count)
@@ -1111,8 +1119,12 @@ class Function(object):
core.BNFreeRegisterList(flags)
return result
- def create_graph(self):
- return FunctionGraph(self._view, core.BNCreateFunctionGraph(self.handle))
+ def create_graph(self, graph_type = FunctionGraphType.NormalFunctionGraph, settings = None):
+ if settings is not None:
+ settings_obj = settings.handle
+ else:
+ settings_obj = None
+ return binaryninja.flowgraph.CoreFlowGraph(core.BNCreateFunctionGraph(self.handle, graph_type, settings_obj))
def apply_imported_types(self, sym):
core.BNApplyImportedTypes(self.handle, sym.handle)
@@ -1250,13 +1262,13 @@ class Function(object):
core.BNSetAutoFunctionCanReturn(self.handle, bc)
def set_auto_stack_adjustment(self, value):
- sc = core.BNSizeWithConfidence()
- sc.value = int(value)
+ oc = core.BNOffsetWithConfidence()
+ oc.value = int(value)
if hasattr(value, 'confidence'):
- sc.confidence = value.confidence
+ oc.confidence = value.confidence
else:
- sc.confidence = types.max_confidence
- core.BNSetAutoFunctionStackAdjustment(self.handle, sc)
+ oc.confidence = types.max_confidence
+ core.BNSetAutoFunctionStackAdjustment(self.handle, oc)
def set_auto_reg_stack_adjustments(self, value):
adjust = (core.BNRegisterStackAdjustment * len(value))()
@@ -1466,6 +1478,7 @@ class Function(object):
result = []
for i in range(0, count.value):
addr = lines[i].addr
+ color = highlight.HighlightColor._from_core_struct(lines[i].highlight)
tokens = []
for j in range(0, lines[i].count):
token_type = InstructionTextTokenType(lines[i].tokens[j].type)
@@ -1477,7 +1490,7 @@ class Function(object):
confidence = lines[i].tokens[j].confidence
address = lines[i].tokens[j].address
tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
- result.append(DisassemblyTextLine(addr, tokens))
+ result.append(DisassemblyTextLine(tokens, addr, color = color))
core.BNFreeDisassemblyTextLines(lines, count.value)
return result
@@ -1573,6 +1586,15 @@ class Function(object):
result = types.RegisterStackAdjustmentWithConfidence(adjust.adjustment, confidence = adjust.confidence)
return result
+ def is_call_instruction(self, addr, arch=None):
+ if arch is None:
+ arch = self.arch
+ return core.BNIsCallInstruction(self.handle, arch.handle, addr)
+
+ def request_debug_report(self, name):
+ core.BNRequestFunctionDebugReport(self.handle, name)
+ self.view.update_analysis()
+
class AdvancedFunctionAnalysisDataRequestor(object):
def __init__(self, func = None):
@@ -1603,10 +1625,18 @@ class AdvancedFunctionAnalysisDataRequestor(object):
class DisassemblyTextLine(object):
- def __init__(self, addr, tokens, il_instr = None):
- self.address = addr
+ def __init__(self, tokens, address = None, il_instr = None, color = None):
+ self.address = address
self.tokens = tokens
self.il_instruction = il_instr
+ if color is None:
+ self.highlight = highlight.HighlightColor()
+ else:
+ 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.highlight = color
def __str__(self):
result = ""
@@ -1615,192 +1645,11 @@ class DisassemblyTextLine(object):
return result
def __repr__(self):
+ if self.address is None:
+ return str(self)
return "<%#x: %s>" % (self.address, str(self))
-class FunctionGraphEdge(object):
- def __init__(self, branch_type, source, target, points, back_edge):
- self.type = BranchType(branch_type)
- self.source = source
- self.target = target
- self.points = points
- self.back_edge = back_edge
-
- def __repr__(self):
- return "<%s: %s>" % (self.type.name, repr(self.target))
-
-
-class FunctionGraphBlock(object):
- def __init__(self, handle, graph):
- self.handle = handle
- self.graph = graph
-
- def __del__(self):
- core.BNFreeFunctionGraphBlock(self.handle)
-
- def __eq__(self, value):
- if not isinstance(value, FunctionGraphBlock):
- return False
- return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
-
- def __ne__(self, value):
- if not isinstance(value, FunctionGraphBlock):
- return True
- return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
-
- @property
- def basic_block(self):
- """Basic block associated with this part of the function graph (read-only)"""
- block = core.BNGetFunctionGraphBasicBlock(self.handle)
- func_handle = core.BNGetBasicBlockFunction(block)
- if func_handle is None:
- core.BNFreeBasicBlock(block)
- return None
-
- view = binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func_handle))
- func = Function(view, func_handle)
-
- if core.BNIsLowLevelILBasicBlock(block):
- block = binaryninja.lowlevelil.LowLevelILBasicBlock(view, block,
- lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func))
- elif core.BNIsMediumLevelILBasicBlock(block):
- block = binaryninja.mediumlevelil.MediumLevelILBasicBlock(view, block,
- mediumlevelil.MediumLevelILFunction(func.arch, core.BNGetBasicBlockMediumLevelILFunction(block), func))
- else:
- block = binaryninja.basicblock.BasicBlock(view, block)
- return block
-
- @property
- def arch(self):
- """Function graph block architecture (read-only)"""
- arch = core.BNGetFunctionGraphBlockArchitecture(self.handle)
- if arch is None:
- return None
- return binaryninja.architecture.CoreArchitecture._from_cache(arch)
-
- @property
- def start(self):
- """Function graph block start (read-only)"""
- return core.BNGetFunctionGraphBlockStart(self.handle)
-
- @property
- def end(self):
- """Function graph block end (read-only)"""
- return core.BNGetFunctionGraphBlockEnd(self.handle)
-
- @property
- def x(self):
- """Function graph block X (read-only)"""
- return core.BNGetFunctionGraphBlockX(self.handle)
-
- @property
- def y(self):
- """Function graph block Y (read-only)"""
- return core.BNGetFunctionGraphBlockY(self.handle)
-
- @property
- def width(self):
- """Function graph block width (read-only)"""
- return core.BNGetFunctionGraphBlockWidth(self.handle)
-
- @property
- def height(self):
- """Function graph block height (read-only)"""
- return core.BNGetFunctionGraphBlockHeight(self.handle)
-
- @property
- def lines(self):
- """Function graph block list of lines (read-only)"""
- count = ctypes.c_ulonglong()
- lines = core.BNGetFunctionGraphBlockLines(self.handle, count)
- block = self.basic_block
- result = []
- for i in range(0, count.value):
- addr = lines[i].addr
- if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'):
- il_instr = block.il_function[lines[i].instrIndex]
- else:
- il_instr = None
- tokens = []
- for j in range(0, lines[i].count):
- token_type = InstructionTextTokenType(lines[i].tokens[j].type)
- text = lines[i].tokens[j].text
- value = lines[i].tokens[j].value
- size = lines[i].tokens[j].size
- operand = lines[i].tokens[j].operand
- context = lines[i].tokens[j].context
- confidence = lines[i].tokens[j].confidence
- address = lines[i].tokens[j].address
- tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
- result.append(DisassemblyTextLine(addr, tokens, il_instr))
- core.BNFreeDisassemblyTextLines(lines, count.value)
- return result
-
- @property
- def outgoing_edges(self):
- """Function graph block list of outgoing edges (read-only)"""
- count = ctypes.c_ulonglong()
- edges = core.BNGetFunctionGraphBlockOutgoingEdges(self.handle, count)
- result = []
- for i in range(0, count.value):
- branch_type = BranchType(edges[i].type)
- target = edges[i].target
- if target:
- func = core.BNGetBasicBlockFunction(target)
- if func is None:
- core.BNFreeBasicBlock(target)
- target = None
- else:
- target = binaryninja.basicblock.BasicBlock(binaryninja.binaryview.BinaryView(handle = core.BNGetFunctionData(func)),
- core.BNNewBasicBlockReference(target))
- core.BNFreeFunction(func)
- points = []
- for j in range(0, edges[i].pointCount):
- points.append((edges[i].points[j].x, edges[i].points[j].y))
- result.append(FunctionGraphEdge(branch_type, self, target, points, edges[i].backEdge))
- core.BNFreeFunctionGraphBlockOutgoingEdgeList(edges, count.value)
- return result
-
- def __setattr__(self, name, value):
- try:
- object.__setattr__(self, name, value)
- except AttributeError:
- raise AttributeError("attribute '%s' is read only" % name)
-
- def __repr__(self):
- arch = self.arch
- if arch:
- return "<graph block: %s@%#x-%#x>" % (arch.name, self.start, self.end)
- else:
- return "<graph block: %#x-%#x>" % (self.start, self.end)
-
- def __iter__(self):
- count = ctypes.c_ulonglong()
- lines = core.BNGetFunctionGraphBlockLines(self.handle, count)
- block = self.basic_block
- try:
- for i in range(0, count.value):
- addr = lines[i].addr
- if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'):
- il_instr = block.il_function[lines[i].instrIndex]
- else:
- il_instr = None
- tokens = []
- for j in range(0, lines[i].count):
- token_type = InstructionTextTokenType(lines[i].tokens[j].type)
- text = lines[i].tokens[j].text
- value = lines[i].tokens[j].value
- size = lines[i].tokens[j].size
- operand = lines[i].tokens[j].operand
- context = lines[i].tokens[j].context
- confidence = lines[i].tokens[j].confidence
- address = lines[i].tokens[j].address
- tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence))
- yield DisassemblyTextLine(addr, tokens, il_instr)
- finally:
- core.BNFreeDisassemblyTextLines(lines, count.value)
-
-
class DisassemblySettings(object):
def __init__(self, handle = None):
if handle is None:
@@ -1838,198 +1687,6 @@ class DisassemblySettings(object):
core.BNSetDisassemblySettingsOption(self.handle, option, state)
-_pending_function_graph_completion_events = {}
-class FunctionGraph(object):
- def __init__(self, view, handle):
- self.view = view
- self.handle = handle
- self._on_complete = None
- self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._complete)
-
- def __del__(self):
- self.abort()
- core.BNFreeFunctionGraph(self.handle)
-
- def __eq__(self, value):
- if not isinstance(value, FunctionGraph):
- return False
- return ctypes.addressof(self.handle.contents) == ctypes.addressof(value.handle.contents)
-
- def __ne__(self, value):
- if not isinstance(value, FunctionGraph):
- return True
- return ctypes.addressof(self.handle.contents) != ctypes.addressof(value.handle.contents)
-
- @property
- def function(self):
- """Function for a function graph (read-only)"""
- func = core.BNGetFunctionForFunctionGraph(self.handle)
- if func is None:
- return None
- return Function(self.view, func)
-
- @property
- def complete(self):
- """Whether function graph layout is complete (read-only)"""
- return core.BNIsFunctionGraphLayoutComplete(self.handle)
-
- @property
- def type(self):
- """Function graph type (read-only)"""
- return FunctionGraphType(core.BNGetFunctionGraphType(self.handle))
-
- @property
- def blocks(self):
- """List of basic blocks in function (read-only)"""
- count = ctypes.c_ulonglong()
- blocks = core.BNGetFunctionGraphBlocks(self.handle, count)
- result = []
- for i in range(0, count.value):
- result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self))
- core.BNFreeFunctionGraphBlockList(blocks, count.value)
- return result
-
- @property
- def has_blocks(self):
- """Whether the function graph has at least one block (read-only)"""
- return core.BNFunctionGraphHasBlocks(self.handle)
-
- @property
- def width(self):
- """Function graph width (read-only)"""
- return core.BNGetFunctionGraphWidth(self.handle)
-
- @property
- def height(self):
- """Function graph height (read-only)"""
- return core.BNGetFunctionGraphHeight(self.handle)
-
- @property
- def horizontal_block_margin(self):
- return core.BNGetHorizontalFunctionGraphBlockMargin(self.handle)
-
- @horizontal_block_margin.setter
- def horizontal_block_margin(self, value):
- core.BNSetFunctionGraphBlockMargins(self.handle, value, self.vertical_block_margin)
-
- @property
- def vertical_block_margin(self):
- return core.BNGetVerticalFunctionGraphBlockMargin(self.handle)
-
- @vertical_block_margin.setter
- def vertical_block_margin(self, value):
- core.BNSetFunctionGraphBlockMargins(self.handle, self.horizontal_block_margin, value)
-
- @property
- def settings(self):
- return DisassemblySettings(core.BNGetFunctionGraphSettings(self.handle))
-
- @property
- def is_il(self):
- return core.BNIsILFunctionGraph(self.handle)
-
- @property
- def is_low_level_il(self):
- return core.BNIsLowLevelILFunctionGraph(self.handle)
-
- @property
- def is_medium_level_il(self):
- return core.BNIsMediumLevelILFunctionGraph(self.handle)
-
- @property
- def il_function(self):
- if self.is_low_level_il:
- il_func = core.BNGetFunctionGraphLowLevelILFunction(self.handle)
- if not il_func:
- return None
- return binaryninja.lowlevelil.LowLevelILFunction(self.function.arch, il_func, self.function)
- if self.is_medium_level_il:
- il_func = core.BNGetFunctionGraphMediumLevelILFunction(self.handle)
- if not il_func:
- return None
- return binaryninja.mediumlevelil.MediumLevelILFunction(self.function.arch, il_func, self.function)
- return None
-
- def __setattr__(self, name, value):
- try:
- object.__setattr__(self, name, value)
- except AttributeError:
- raise AttributeError("attribute '%s' is read only" % name)
-
- def __repr__(self):
- return "<graph of %s>" % repr(self.function)
-
- def __iter__(self):
- count = ctypes.c_ulonglong()
- blocks = core.BNGetFunctionGraphBlocks(self.handle, count)
- try:
- for i in range(0, count.value):
- yield FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self)
- finally:
- core.BNFreeFunctionGraphBlockList(blocks, count.value)
-
- def _complete(self, ctxt):
- try:
- if self._on_complete is not None:
- self._on_complete()
- global _pending_function_graph_completion_events
- if id(self) in _pending_function_graph_completion_events:
- del _pending_function_graph_completion_events[id(self)]
- except:
- log.log_error(traceback.format_exc())
-
- def layout(self, graph_type = FunctionGraphType.NormalFunctionGraph):
- if isinstance(graph_type, str):
- graph_type = FunctionGraphType[graph_type]
- core.BNStartFunctionGraphLayout(self.handle, graph_type)
-
- def _wait_complete(self):
- self._wait_cond.acquire()
- self._wait_cond.notify()
- self._wait_cond.release()
-
- def layout_and_wait(self, graph_type=FunctionGraphType.NormalFunctionGraph):
- self._wait_cond = threading.Condition()
- self.on_complete(self._wait_complete)
- self.layout(graph_type)
-
- self._wait_cond.acquire()
- while not self.complete:
- self._wait_cond.wait()
- self._wait_cond.release()
-
- def on_complete(self, callback):
- global _pending_function_graph_completion_events
- _pending_function_graph_completion_events[id(self)] = self
- self._on_complete = callback
- core.BNSetFunctionGraphCompleteCallback(self.handle, None, self._cb)
-
- def abort(self):
- core.BNAbortFunctionGraph(self.handle)
- global _pending_function_graph_completion_events
- if id(self) in _pending_function_graph_completion_events:
- del _pending_function_graph_completion_events[id(self)]
-
- def get_blocks_in_region(self, left, top, right, bottom):
- count = ctypes.c_ulonglong()
- blocks = core.BNGetFunctionGraphBlocksInRegion(self.handle, left, top, right, bottom, count)
- result = []
- for i in range(0, count.value):
- result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self))
- core.BNFreeFunctionGraphBlockList(blocks, count.value)
- return result
-
- def is_option_set(self, option):
- if isinstance(option, str):
- option = DisassemblyOption[option]
- return core.BNIsFunctionGraphOptionSet(self.handle, option)
-
- def set_option(self, option, state = True):
- if isinstance(option, str):
- option = DisassemblyOption[option]
- core.BNSetFunctionGraphOption(self.handle, option, state)
-
-
class RegisterInfo(object):
def __init__(self, full_width_reg, size, offset=0, extend=ImplicitRegisterExtend.NoExtend, index=None):
self.full_width_reg = full_width_reg
diff --git a/python/highlight.py b/python/highlight.py
index 55246a9a..502caa80 100644
--- a/python/highlight.py
+++ b/python/highlight.py
@@ -110,3 +110,13 @@ class HighlightColor(object):
result.b = self.blue
return result
+
+ @staticmethod
+ def _from_core_struct(color):
+ if color.style == HighlightColorStyle.StandardHighlightColor:
+ return HighlightColor(color=color.color, alpha=color.alpha)
+ elif color.style == HighlightColorStyle.MixedHighlightColor:
+ return HighlightColor(color=color.color, mix_color=color.mixColor, mix=color.mix, alpha=color.alpha)
+ elif color.style == HighlightColorStyle.CustomHighlightColor:
+ return HighlightColor(red=color.r, green=color.g, blue=color.b, alpha=color.alpha)
+ return HighlightColor(color=HighlightStandardColor.NoHighlightColor)
diff --git a/python/interaction.py b/python/interaction.py
index 49b4e024..e53312cf 100644
--- a/python/interaction.py
+++ b/python/interaction.py
@@ -23,8 +23,10 @@ import traceback
# Binary Ninja components
from binaryninja import _binaryninjacore as core
-from binaryninja.enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult
+from binaryninja.enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, MessageBoxButtonResult, ReportType
from binaryninja import binaryview
+from binaryninja import log
+from binaryninja import flowgraph
# 2-3 compatibility
from binaryninja import range
@@ -255,6 +257,8 @@ class InteractionHandler(object):
self._cb.showPlainTextReport = self._cb.showPlainTextReport.__class__(self._show_plain_text_report)
self._cb.showMarkdownReport = self._cb.showMarkdownReport.__class__(self._show_markdown_report)
self._cb.showHTMLReport = self._cb.showHTMLReport.__class__(self._show_html_report)
+ self._cb.showGraphReport = self._cb.showGraphReport.__class__(self._show_graph_report)
+ self._cb.showReportCollection = self._cb.showReportCollection.__class__(self._show_report_collection)
self._cb.getTextLineInput = self._cb.getTextLineInput.__class__(self._get_text_line_input)
self._cb.getIntegerInput = self._cb.getIntegerInput.__class__(self._get_int_input)
self._cb.getAddressInput = self._cb.getAddressInput.__class__(self._get_address_input)
@@ -299,6 +303,22 @@ class InteractionHandler(object):
except:
log.log_error(traceback.format_exc())
+ def _show_graph_report(self, ctxt, view, title, graph):
+ try:
+ if view:
+ view = binaryview.BinaryView(handle = core.BNNewViewReference(view))
+ else:
+ view = None
+ self.show_graph_report(view, title, flowgraph.CoreFlowGraph(core.BNNewFlowGraphReference(graph)))
+ except:
+ log.log_error(traceback.format_exc())
+
+ def _show_report_collection(self, ctxt, title, reports):
+ try:
+ self.show_report_collection(title, ReportCollection(core.BNNewReportCollectionReference(reports)))
+ except:
+ log.log_error(traceback.format_exc())
+
def _get_text_line_input(self, ctxt, result, prompt, title):
try:
value = self.get_text_line_input(prompt, title)
@@ -432,6 +452,12 @@ class InteractionHandler(object):
if len(plaintext) != 0:
self.show_plain_text_report(view, title, plaintext)
+ def show_graph_report(self, view, title, graph):
+ pass
+
+ def show_report_collection(self, title, reports):
+ pass
+
def get_text_line_input(self, prompt, title):
return None
@@ -467,6 +493,123 @@ class InteractionHandler(object):
return MessageBoxButtonResult.CancelButton
+class PlainTextReport(object):
+ def __init__(self, title, contents, view = None):
+ self.view = view
+ self.title = title
+ self.contents = contents
+
+ def __repr__(self):
+ return "<plain text report: %s>" % self.title
+
+ def __str__(self):
+ return self.contents
+
+
+class MarkdownReport(object):
+ def __init__(self, title, contents, plaintext = "", view = None):
+ self.view = view
+ self.title = title
+ self.contents = contents
+ self.plaintext = plaintext
+
+ def __repr__(self):
+ return "<markdown report: %s>" % self.title
+
+ def __str__(self):
+ return self.contents
+
+
+class HTMLReport(object):
+ def __init__(self, title, contents, plaintext = "", view = None):
+ self.view = view
+ self.title = title
+ self.contents = contents
+ self.plaintext = plaintext
+
+ def __repr__(self):
+ return "<html report: %s>" % self.title
+
+ def __str__(self):
+ return self.contents
+
+
+class FlowGraphReport(object):
+ def __init__(self, title, graph, view = None):
+ self.view = view
+ self.title = title
+ self.graph = graph
+
+ def __repr__(self):
+ return "<graph report: %s>" % self.title
+
+
+class ReportCollection(object):
+ def __init__(self, handle = None):
+ if handle is None:
+ self.handle = core.BNCreateReportCollection()
+ else:
+ self.handle = handle
+
+ def __len__(self):
+ return core.BNGetReportCollectionCount(self.handle)
+
+ def _report_from_index(self, i):
+ report_type = core.BNGetReportType(self.handle, i)
+ title = core.BNGetReportTitle(self.handle, i)
+ view = core.BNGetReportView(self.handle, i)
+ if view:
+ view = binaryview.BinaryView(handle = view)
+ else:
+ view = None
+ if report_type == ReportType.PlainTextReportType:
+ contents = core.BNGetReportContents(self.handle, i)
+ return PlainTextReport(title, contents, view)
+ elif report_type == ReportType.MarkdownReportType:
+ contents = core.BNGetReportContents(self.handle, i)
+ plaintext = core.BNGetReportPlainText(self.handle, i)
+ return MarkdownReport(title, contents, plaintext, view)
+ elif report_type == ReportType.HTMLReportType:
+ contents = core.BNGetReportContents(self.handle, i)
+ plaintext = core.BNGetReportPlainText(self.handle, i)
+ return HTMLReport(title, contents, plaintext, view)
+ elif report_type == ReportType.FlowGraphReportType:
+ graph = flowgraph.CoreFlowGraph(core.BNGetReportFlowGraph(self.handle, i))
+ return FlowGraphReport(title, graph, view)
+ raise TypeError("invalid report type %s" % repr(report_type))
+
+ def __getitem__(self, i):
+ if isinstance(i, slice) or isinstance(i, tuple):
+ raise IndexError("expected integer report index")
+ if (i < 0) or (i >= len(self)):
+ raise IndexError("index out of range")
+ return self._report_from_index(i)
+
+ def __iter__(self):
+ count = len(self)
+ for i in xrange(0, count):
+ yield self._report_from_index(i)
+
+ def __repr__(self):
+ return "<reports: %s>" % repr(list(self))
+
+ def append(self, report):
+ if report.view is None:
+ view = None
+ else:
+ view = report.view.handle
+ if isinstance(report, PlainTextReport):
+ core.BNAddPlainTextReportToCollection(self.handle, view, report.title, report.contents)
+ elif isinstance(report, MarkdownReport):
+ core.BNAddMarkdownReportToCollection(self.handle, view, report.title, report.contents, report.plaintext)
+ elif isinstance(report, HTMLReport):
+ core.BNAddHTMLReportToCollection(self.handle, view, report.title, report.contents, report.plaintext)
+ elif isinstance(report, FlowGraphReport):
+ core.BNAddGraphReportToCollection(self.handle, view, report.title, report.graph.handle)
+ else:
+ raise TypeError("expected report object")
+
+
def markdown_to_html(contents):
"""
``markdown_to_html`` converts the provided markdown to HTML.
@@ -533,6 +676,34 @@ def show_html_report(title, contents, plaintext=""):
core.BNShowHTMLReport(None, title, contents, plaintext)
+def show_graph_report(title, graph):
+ """
+ ``show_graph_report`` displays a flow graph in UI applications.
+
+ Note: This API function will have no effect outside the UI.
+
+ :param FlowGraph graph: Flow graph to display
+ :rtype: None
+ """
+ func = graph.function
+ if func is None:
+ core.BNShowGraphReport(None, title, graph.handle)
+ else:
+ core.BNShowGraphReport(func.view.handle, title, graph.handle)
+
+
+def show_report_collection(title, reports):
+ """
+ ``show_report_collection`` displays mulitple reports in UI applications.
+
+ Note: This API function will have no effect outside the UI.
+
+ :param ReportCollection reports: Reports to display
+ :rtype: None
+ """
+ core.BNShowReportCollection(title, reports.handle)
+
+
def get_text_line_input(prompt, title):
"""
``get_text_line_input`` prompts the user to input a string with the given prompt and title.
diff --git a/python/lowlevelil.py b/python/lowlevelil.py
index f7f8926c..3d330aa9 100644
--- a/python/lowlevelil.py
+++ b/python/lowlevelil.py
@@ -366,6 +366,7 @@ class LowLevelILInstruction(object):
name, operand_type = operand
if operand_type == "int":
value = instr.operands[i]
+ value = (value & ((1 << 63) - 1)) - (value & (1 << 63))
elif operand_type == "float":
if instr.size == 4:
value = struct.unpack("f", struct.pack("I", instr.operands[i] & 0xffffffff))[0]
@@ -734,9 +735,9 @@ class LowLevelILFunction(object):
if handle is not None:
self.handle = core.handle_of_type(handle, core.BNLowLevelILFunction)
else:
- func_handle = None
- if self.source_function is not None:
- func_handle = self.source_function.handle
+ if self.source_function is None:
+ raise ValueError("IL functions must be created with an associated function")
+ func_handle = self.source_function.handle
self.handle = core.BNCreateLowLevelILFunction(arch.handle, func_handle)
def __del__(self):
@@ -2365,6 +2366,13 @@ class LowLevelILFunction(object):
return None
return result
+ def create_graph(self, settings = None):
+ if settings is not None:
+ settings_obj = settings.handle
+ else:
+ settings_obj = None
+ return binaryninja.flowgraph.CoreFlowGraph(core.BNCreateLowLevelILFunctionGraph(self.handle, settings_obj))
+
class LowLevelILBasicBlock(basicblock.BasicBlock):
def __init__(self, view, handle, owner):
diff --git a/python/mainthread.py b/python/mainthread.py
index 5b0cd53c..c63e3ff8 100644
--- a/python/mainthread.py
+++ b/python/mainthread.py
@@ -21,13 +21,14 @@
# Binary Ninja components
from binaryninja import _binaryninjacore as core
from binaryninja import scriptingprovider
+from binaryninja import plugin
def execute_on_main_thread(func):
action = scriptingprovider._ThreadActionContext(func)
obj = core.BNExecuteOnMainThread(0, action.callback)
if obj:
- return scriptingprovider.MainThreadAction(obj)
+ return plugin.MainThreadAction(obj)
return None
diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py
index a506767c..93c45dcc 100644
--- a/python/mediumlevelil.py
+++ b/python/mediumlevelil.py
@@ -22,6 +22,7 @@ import ctypes
import struct
# Binary Ninja components
+import binaryninja
from binaryninja import _binaryninjacore as core
from binaryninja.enums import MediumLevelILOperation, InstructionTextTokenType, ILBranchDependence
from binaryninja import basicblock #required for MediumLevelILBasicBlock argument
@@ -129,6 +130,7 @@ class MediumLevelILInstruction(object):
MediumLevelILOperation.MLIL_LOW_PART: [("src", "expr")],
MediumLevelILOperation.MLIL_JUMP: [("dest", "expr")],
MediumLevelILOperation.MLIL_JUMP_TO: [("dest", "expr"), ("targets", "int_list")],
+ MediumLevelILOperation.MLIL_RET_HINT: [("dest", "expr")],
MediumLevelILOperation.MLIL_CALL: [("output", "var_list"), ("dest", "expr"), ("params", "expr_list")],
MediumLevelILOperation.MLIL_CALL_UNTYPED: [("output", "expr"), ("dest", "expr"), ("params", "expr"), ("stack", "expr")],
MediumLevelILOperation.MLIL_CALL_OUTPUT: [("dest", "var_list")],
@@ -230,6 +232,7 @@ class MediumLevelILInstruction(object):
name, operand_type = operand
if operand_type == "int":
value = instr.operands[i]
+ value = (value & ((1 << 63) - 1)) - (value & (1 << 63))
elif operand_type == "float":
if instr.size == 4:
value = struct.unpack("f", struct.pack("I", instr.operands[i] & 0xffffffff))[0]
@@ -615,9 +618,9 @@ class MediumLevelILFunction(object):
if handle is not None:
self.handle = core.handle_of_type(handle, core.BNMediumLevelILFunction)
else:
- func_handle = None
- if self.source_function is not None:
- func_handle = self.source_function.handle
+ if self.source_function is None:
+ raise ValueError("IL functions must be created with an associated function")
+ func_handle = self.source_function.handle
self.handle = core.BNCreateMediumLevelILFunction(arch.handle, func_handle)
def __del__(self):
@@ -938,6 +941,13 @@ class MediumLevelILFunction(object):
return None
return result
+ def create_graph(self, settings = None):
+ if settings is not None:
+ settings_obj = settings.handle
+ else:
+ settings_obj = None
+ return binaryninja.flowgraph.CoreFlowGraph(core.BNCreateMediumLevelILFunctionGraph(self.handle, settings_obj))
+
class MediumLevelILBasicBlock(basicblock.BasicBlock):
def __init__(self, view, handle, owner):
diff --git a/python/types.py b/python/types.py
index b78b7109..38d7b846 100644
--- a/python/types.py
+++ b/python/types.py
@@ -626,7 +626,7 @@ class Type(object):
elif not isinstance(stack_adjust, SizeWithConfidence):
stack_adjust = SizeWithConfidence(stack_adjust)
- stack_adjust_conf = core.BNSizeWithConfidence()
+ stack_adjust_conf = core.BNOffsetWithConfidence()
stack_adjust_conf.value = stack_adjust.value
stack_adjust_conf.confidence = stack_adjust.confidence
diff --git a/type.cpp b/type.cpp
index 81d2ec26..37b8f131 100644
--- a/type.cpp
+++ b/type.cpp
@@ -604,10 +604,10 @@ uint64_t Type::GetOffset() const
}
-Confidence<size_t> Type::GetStackAdjustment() const
+Confidence<int64_t> Type::GetStackAdjustment() const
{
- BNSizeWithConfidence result = BNGetTypeStackAdjustment(m_object);
- return Confidence<size_t>(result.value, result.confidence);
+ BNOffsetWithConfidence result = BNGetTypeStackAdjustment(m_object);
+ return Confidence<int64_t>(result.value, result.confidence);
}
@@ -823,7 +823,7 @@ Ref<Type> Type::ArrayType(const Confidence<Ref<Type>>& type, uint64_t elem)
Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue,
const Confidence<Ref<CallingConvention>>& callingConvention,
const std::vector<FunctionParameter>& params, const Confidence<bool>& varArg,
- const Confidence<size_t>& stackAdjust)
+ const Confidence<int64_t>& stackAdjust)
{
BNTypeWithConfidence returnValueConf;
returnValueConf.type = returnValue->GetObject();
@@ -849,7 +849,7 @@ Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue,
varArgConf.value = varArg.GetValue();
varArgConf.confidence = varArg.GetConfidence();
- BNSizeWithConfidence stackAdjustConf;
+ BNOffsetWithConfidence stackAdjustConf;
stackAdjustConf.value = stackAdjust.GetValue();
stackAdjustConf.confidence = stackAdjust.GetConfidence();