summaryrefslogtreecommitdiff
path: root/examples/workflows/tailcall/tailcall.cpp
blob: 0fed369d2f3896e14a88786053d59d109419a366 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#define _CRT_SECURE_NO_WARNINGS

#include <cinttypes>
#include <cstdint>
#include <cstdio>
#include <string>
#include <tuple>
#include <unordered_map>

#include "binaryninjaapi.h"
#include "lowlevelilinstruction.h"
#include "mediumlevelilinstruction.h"


using namespace BinaryNinja;
using namespace std;

#if defined(_MSC_VER)
	#define snprintf _snprintf
#endif


extern "C"
{
	BN_DECLARE_CORE_ABI_VERSION

	void TailCallTranslation(Ref<AnalysisContext> analysisContext)
	{
		Ref<Function> function = analysisContext->GetFunction();
		Ref<BinaryView> data = function->GetView();

		bool updated = false;
		uint8_t opcode[BN_MAX_INSTRUCTION_LENGTH];
		InstructionInfo iInfo;

		// Look for jumps to other functions
		Ref<LowLevelILFunction> llilFunc = analysisContext->GetLowLevelILFunction();
		for (auto& i : llilFunc->GetBasicBlocks())
		{
			// if (m_owner->IsAborted())
			// 	return;

			Ref<Architecture> arch = i->GetArchitecture();
			size_t instrIndex = i->GetEnd() - 1;
			LowLevelILInstruction instr = llilFunc->GetInstruction(instrIndex);
			if (instr.operation != LLIL_JUMP)
				continue;

			uint64_t platformAddr;
			LowLevelILInstruction destExpr = instr.GetDestExpr<LLIL_JUMP>();
			RegisterValue target = destExpr.GetValue();
			if (target.IsConstant())
				platformAddr = target.value;
			else if (target.state
			         == ImportedAddressValue)  // Call to imported function, look up type from import symbol
				platformAddr = target.value;
			else if (target.state == ExternalPointerValue && target.offset == 0)
				platformAddr = target.value;
			else
				continue;

			size_t opLen = data->Read(opcode, instr.address, arch->GetMaxInstructionLength());
			if (!opLen || !arch->GetInstructionInfo(opcode, instr.address, opLen, iInfo))
				continue;
			Ref<Platform> platform = iInfo.archTransitionByTargetAddr ?
                                         function->GetPlatform()->GetAssociatedPlatformByAddress(platformAddr) :
                                         function->GetPlatform();
			if (platform)
			{
				bool canReturn = true;
				Ref<Function> targetFunc = nullptr;
				if (target.state == ImportedAddressValue)
				{
					DataVariable var;
					if (data->GetDataVariableAtAddress(target.value, var))
					{
						if (var.type.GetValue() && (var.type->GetClass() == PointerTypeClass)
							&& (var.type->GetChildType()->GetClass() == FunctionTypeClass))
							canReturn = var.type->GetChildType()->CanReturn().GetValue();
					}
				}
				else if (target.state == ExternalPointerValue && target.offset == 0)
				{
					targetFunc = data->GetAnalysisFunction(platform, platformAddr);
					if (targetFunc)
						canReturn = targetFunc->CanReturn();
				}
				else
				{
					targetFunc = data->GetAnalysisFunction(platform, platformAddr);
					if (targetFunc)
						canReturn = targetFunc->CanReturn();
					else
						continue;
				}

				updated = true;
				instr.Replace(llilFunc->TailCall(destExpr.exprIndex, instr));
				analysisContext->Inform("directRefs", "insert", platformAddr, i->GetArchitecture(), instr.address);

				if (!canReturn)
				{
					analysisContext->Inform("directNoReturnCalls", "insert", i->GetArchitecture(), instr.address);
					i->GetSourceBlock()->SetCanExit(false);
					i->SetCanExit(false);
				}
			}
		}

		if (!updated)
			return;

		// Updates found, regenerate SSA form
		llilFunc->GenerateSSAForm();
	}


	BINARYNINJAPLUGIN bool CorePluginInit()
	{
		Ref<Workflow> customTailCallWorkflow = Workflow::Instance("core.function.baseAnalysis")->Clone("CustomTailCallWorkflow");
		customTailCallWorkflow->RegisterActivity(new Activity("extension.translateTailCalls", &TailCallTranslation));
		customTailCallWorkflow->Replace("core.function.translateTailCalls", "extension.translateTailCalls");
		customTailCallWorkflow->Remove("core.function.translateTailCalls");
		Workflow::RegisterWorkflow(customTailCallWorkflow,
		    R"#({
			"title" : "Tail Call Translation (Example)",
			"description" : "This analysis stands in as an example to demonstrate Binary Ninja's extensible analysis APIs.",
			"targetType" : "function"
			})#");

		return true;
	}
}