mirror of
https://github.com/avast/retdec.git
synced 2025-02-17 04:08:09 +00:00
symbolic_tree: fix WIP
This commit is contained in:
parent
33c02796fe
commit
2a374d918a
@ -10,6 +10,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h"
|
||||
#include "retdec/utils/value.h"
|
||||
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
@ -17,6 +18,105 @@
|
||||
namespace retdec {
|
||||
namespace bin2llvmir {
|
||||
|
||||
class ArgumentEntry
|
||||
{
|
||||
public:
|
||||
typedef std::shared_ptr<ArgumentEntry> Ptr;
|
||||
|
||||
protected:
|
||||
ArgumentEntry();
|
||||
ArgumentEntry(
|
||||
llvm::Type* type = nullptr,
|
||||
const std::string& name = "");
|
||||
|
||||
public:
|
||||
void setType(llvm::Type* type);
|
||||
void setName(const std::string& name);
|
||||
|
||||
std::pair<llvm::Value*, llvm::Type*> get(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a) const;
|
||||
|
||||
std::pair<llvm::Value*, std::string> get(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix,
|
||||
const std::string& base = "") const;
|
||||
|
||||
llvm::Type* getType(llvm::Function* fnc, const Abi& a) const;
|
||||
llvm::Value* getValue(llvm::Function* fnc, const Abi& a) const;
|
||||
|
||||
bool isDefined(llvm::Function* fnc, const Abi& a) const;
|
||||
|
||||
std::string getName(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix = "",
|
||||
const std::string& base = "") const;
|
||||
|
||||
protected:
|
||||
virtual llvm::Value* fetchArgValue(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a) const;
|
||||
|
||||
virtual std::string createName(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix = "",
|
||||
const std::string& base = "") const;
|
||||
|
||||
private:
|
||||
llvm::Type* _type = nullptr;
|
||||
std::string _name = "";
|
||||
};
|
||||
|
||||
|
||||
class DummyArgumentEntry: public ArgumentEntry {
|
||||
public:
|
||||
DummyArgumentEntry(
|
||||
llvm::Type* type = nullptr,
|
||||
const std::string& name = "");
|
||||
|
||||
~DummyArgumentEntry();
|
||||
};
|
||||
|
||||
template<typename ArgID>
|
||||
class ArgumentEntryImpl : public ArgumentEntry
|
||||
{
|
||||
public:
|
||||
ArgumentEntryImpl(
|
||||
ArgID argid,
|
||||
llvm::Type* type = nullptr,
|
||||
const std::string& name = "");
|
||||
|
||||
~ArgumentEntryImpl();
|
||||
|
||||
virtual llvm::Value* fetchArgValue(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a) const override;
|
||||
|
||||
virtual std::string createName(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix = "",
|
||||
const std::string& base = "") const override;
|
||||
|
||||
private:
|
||||
ArgID _argid;
|
||||
};
|
||||
|
||||
template class ArgumentEntryImpl<int>;
|
||||
typedef ArgumentEntryImpl<int> StackArgumentEntry;
|
||||
|
||||
template class ArgumentEntryImpl<std::size_t>;
|
||||
typedef ArgumentEntryImpl<std::size_t> FunctionArgumentEntry;
|
||||
|
||||
template class ArgumentEntryImpl<unsigned int>;
|
||||
typedef ArgumentEntryImpl<unsigned int> RegisterArgumentEntry;
|
||||
|
||||
template class ArgumentEntryImpl<llvm::Constant*>;
|
||||
typedef ArgumentEntryImpl<llvm::Constant*> ConstantArgumentEntry;
|
||||
|
||||
class ReturnEntry
|
||||
{
|
||||
public:
|
||||
@ -172,6 +272,10 @@ class DataFlowEntry : public FunctionEntry
|
||||
const std::vector<CallEntry>& callEntries() const;
|
||||
std::vector<CallEntry>& callEntries();
|
||||
|
||||
std::vector<ArgumentEntry::Ptr> tmpArgs;
|
||||
std::map<llvm::ReturnInst*, llvm::Value*> rets2vals;
|
||||
std::map<llvm::CallInst*, std::vector<ArgumentEntry::Ptr>> loadsOfCalls;
|
||||
|
||||
private:
|
||||
llvm::Value* _calledValue = nullptr;
|
||||
|
||||
|
@ -91,11 +91,15 @@ class ParamReturn : public llvm::ModulePass
|
||||
private:
|
||||
void applyToIr();
|
||||
void applyToIr(DataFlowEntry& de);
|
||||
void applyToIrRef(DataFlowEntry& de);
|
||||
void connectWrappers(const DataFlowEntry& de);
|
||||
|
||||
std::map<llvm::CallInst*, std::vector<ArgumentEntry::Ptr>> fetchArgsOfCalls(
|
||||
const std::vector<CallEntry>& calls) const;
|
||||
std::map<llvm::CallInst*, std::vector<llvm::Value*>> fetchLoadsOfCalls(
|
||||
const std::vector<CallEntry>& calls) const;
|
||||
|
||||
|
||||
private:
|
||||
llvm::Module* _module = nullptr;
|
||||
Config* _config = nullptr;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h" //TODO: This should be moved to .*/providers/
|
||||
#include "retdec/bin2llvmir/providers/abi/abi.h"
|
||||
#include "retdec/bin2llvmir/providers/config.h"
|
||||
#include "retdec/bin2llvmir/providers/fileimage.h"
|
||||
@ -90,6 +91,15 @@ class IrModifier
|
||||
bool wideString = false);
|
||||
|
||||
FunctionPair modifyFunction(
|
||||
llvm::Function* fnc,
|
||||
llvm::Type* ret,
|
||||
llvm::Value* retVal = nullptr,
|
||||
const std::vector<ArgumentEntry::Ptr>& args = {},
|
||||
const std::map<llvm::ReturnInst*, llvm::Value*>& rets2vals = {},
|
||||
const std::map<llvm::CallInst*, std::vector<ArgumentEntry::Ptr>>& calls2args = {},
|
||||
bool isVarArg = false);
|
||||
|
||||
FunctionPair modifyFunctionOld(
|
||||
llvm::Function* fnc,
|
||||
llvm::Type* ret,
|
||||
std::vector<llvm::Type*> args,
|
||||
@ -110,6 +120,25 @@ class IrModifier
|
||||
llvm::Value* convertToStructure(
|
||||
llvm::Value* gv,
|
||||
llvm::StructType* strType);
|
||||
|
||||
llvm::Value* convertToPointer(
|
||||
llvm::Value* gv,
|
||||
std::size_t ptrDepth);
|
||||
|
||||
llvm::Value* createStructureFromStacks(
|
||||
llvm::AllocaInst* startStack,
|
||||
llvm::StructType* strType,
|
||||
int offset,
|
||||
llvm::Instruction* before,
|
||||
llvm::InsertValueInst* newStructure = nullptr,
|
||||
std::vector<unsigned int>idxs = {});
|
||||
llvm::Value* extractStructureToStacks(
|
||||
llvm::AllocaInst* startStack,
|
||||
llvm::StructType* strType,
|
||||
int offset,
|
||||
llvm::Instruction* before,
|
||||
llvm::InsertValueInst* newStructure = nullptr,
|
||||
std::vector<unsigned int>idxs = {});
|
||||
protected:
|
||||
llvm::Value* changeObjectDeclarationType(
|
||||
FileImage* objf,
|
||||
|
@ -128,7 +128,9 @@ BIN2LLVMIR_PARAMS = [
|
||||
'-inst-opt',
|
||||
'-cond-branch-opt',
|
||||
'-syscalls',
|
||||
'-dump-module',
|
||||
'-stack',
|
||||
'-dump-module',
|
||||
'-constants',
|
||||
'-dump-module',
|
||||
'-param-return',
|
||||
|
@ -377,6 +377,7 @@ void SymbolicTree::_simplifyNode()
|
||||
Value* val = nullptr;
|
||||
LoadInst* load = nullptr;
|
||||
GlobalVariable* global = nullptr;
|
||||
AllocaInst* local = nullptr;
|
||||
ConstantInt* c1 = nullptr;
|
||||
ConstantInt* c2 = nullptr;
|
||||
|
||||
@ -418,6 +419,11 @@ void SymbolicTree::_simplifyNode()
|
||||
{
|
||||
*this = std::move(ops[0]);
|
||||
}
|
||||
else if (match(*this, m_Load(m_ConstantInt(c1), &load)))
|
||||
{
|
||||
std::cout << "You are genius!" << std::endl;
|
||||
*this = std::move(ops[0]);
|
||||
}
|
||||
else if (match(*this, m_Add(m_ConstantInt(c1), m_ConstantInt(c2))))
|
||||
{
|
||||
value = ConstantInt::get(
|
||||
@ -456,6 +462,15 @@ void SymbolicTree::_simplifyNode()
|
||||
ops.clear();
|
||||
}
|
||||
}
|
||||
else if (match(*this, m_Add(m_Value(val), m_ConstantInt(c1)))
|
||||
&& _config->isStackVariable(val))
|
||||
{
|
||||
auto offset = _config->getStackVariableOffset(val);
|
||||
value = ConstantInt::get(
|
||||
c1->getType(),
|
||||
c1->getSExtValue() + offset);
|
||||
ops.clear();
|
||||
}
|
||||
else if (match(*this, m_Add(m_Value(), m_Zero()))
|
||||
|| match(*this, m_Sub(m_Value(), m_Zero())))
|
||||
{
|
||||
@ -475,6 +490,15 @@ void SymbolicTree::_simplifyNode()
|
||||
c1->getType(),
|
||||
c1->getSExtValue() + c2->getSExtValue());
|
||||
}
|
||||
else if (match(*this, m_Add(m_Value(val), m_ConstantInt(c1)))
|
||||
&& _config->isStackVariable(val))
|
||||
{
|
||||
auto offset = _config->getStackVariableOffset(val);
|
||||
value = ConstantInt::get(
|
||||
c1->getType(),
|
||||
c1->getSExtValue() + offset);
|
||||
ops.clear();
|
||||
}
|
||||
|
||||
// Move Constants from ops[0] to ops[1].
|
||||
//
|
||||
|
@ -5,14 +5,209 @@
|
||||
*/
|
||||
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
|
||||
#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h"
|
||||
#include "retdec/bin2llvmir/providers/abi/abi.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace retdec {
|
||||
namespace bin2llvmir {
|
||||
|
||||
//
|
||||
//=============================================================================
|
||||
// ArgumentEntryImpl
|
||||
//=============================================================================
|
||||
//
|
||||
|
||||
ArgumentEntry::ArgumentEntry(llvm::Type* type, const std::string& name):
|
||||
_type(type),
|
||||
_name(name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::pair<Value*, Type*> ArgumentEntry::get(Function* fnc, const Abi& a) const
|
||||
{
|
||||
|
||||
return {getValue(fnc, a), getType(fnc, a)};
|
||||
}
|
||||
|
||||
std::pair<Value*, std::string> ArgumentEntry::get(
|
||||
Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix,
|
||||
const std::string& base) const
|
||||
{
|
||||
|
||||
return {getValue(fnc, a), getName(fnc, a, suffix, base)};
|
||||
}
|
||||
|
||||
std::string ArgumentEntry::getName(
|
||||
Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix,
|
||||
const std::string& base) const
|
||||
{
|
||||
if (!_name.empty())
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
std::string newBase = base.empty() ? "arg":base;
|
||||
|
||||
return createName(fnc, a, suffix, newBase);
|
||||
}
|
||||
|
||||
Value* ArgumentEntry::getValue(Function* fnc, const Abi& a) const
|
||||
{
|
||||
Value* val = fetchArgValue(fnc, a);
|
||||
|
||||
return val ? val : a.getConfig()->getGlobalDummy();
|
||||
}
|
||||
|
||||
bool ArgumentEntry::isDefined(Function* fnc, const Abi& a) const
|
||||
{
|
||||
return fetchArgValue(fnc, a) != nullptr;
|
||||
}
|
||||
|
||||
Type* ArgumentEntry::getType(Function* fnc, const Abi& a) const
|
||||
{
|
||||
if (_type)
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
auto* val = getValue(fnc, a);
|
||||
assert(val && val->getType()->isPointerTy());
|
||||
return val->getType()->getPointerElementType();
|
||||
}
|
||||
|
||||
llvm::Value* ArgumentEntry::fetchArgValue(llvm::Function* fnc, const Abi& a) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string ArgumentEntry::createName(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix,
|
||||
const std::string& base) const
|
||||
{
|
||||
return base+suffix;
|
||||
}
|
||||
|
||||
void ArgumentEntry::setType(Type* type)
|
||||
{
|
||||
_type = FunctionType::isValidArgumentType(type) ?
|
||||
type : nullptr;
|
||||
}
|
||||
|
||||
DummyArgumentEntry::DummyArgumentEntry(
|
||||
llvm::Type* type,
|
||||
const std::string& name):
|
||||
ArgumentEntry(type, name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DummyArgumentEntry::~DummyArgumentEntry()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename ArgID>
|
||||
ArgumentEntryImpl<ArgID>::ArgumentEntryImpl(
|
||||
ArgID argid,
|
||||
llvm::Type* type,
|
||||
const std::string& name):
|
||||
ArgumentEntry(type, name)
|
||||
{
|
||||
_argid = argid;
|
||||
}
|
||||
|
||||
template<typename ArgID>
|
||||
ArgumentEntryImpl<ArgID>::~ArgumentEntryImpl()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
Value* StackArgumentEntry::fetchArgValue(Function* fnc, const Abi& a) const
|
||||
{
|
||||
return a.getConfig()->getLlvmStackVariable(fnc, _argid);
|
||||
}
|
||||
|
||||
template<>
|
||||
Value* RegisterArgumentEntry::fetchArgValue(Function* fnc, const Abi& a) const
|
||||
{
|
||||
return a.getRegister(_argid);
|
||||
}
|
||||
|
||||
template<>
|
||||
Value* FunctionArgumentEntry::fetchArgValue(Function* fnc, const Abi& a) const
|
||||
{
|
||||
assert(fnc->arg_size() > _argid);
|
||||
return (fnc->arg_begin() + _argid);
|
||||
}
|
||||
|
||||
template<>
|
||||
Value* ConstantArgumentEntry::fetchArgValue(Function* fnc, const Abi& a) const
|
||||
{
|
||||
return _argid;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string StackArgumentEntry::createName(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix,
|
||||
const std::string& base) const
|
||||
{
|
||||
if (suffix.empty())
|
||||
{
|
||||
return base+std::to_string(_argid);
|
||||
}
|
||||
|
||||
return base+suffix;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string RegisterArgumentEntry::createName(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix,
|
||||
const std::string& base) const
|
||||
{
|
||||
if (suffix.empty())
|
||||
{
|
||||
Value* val = getValue(fnc, a);
|
||||
return base+val->getName().str();
|
||||
}
|
||||
return base+suffix;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string FunctionArgumentEntry::createName(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix,
|
||||
const std::string& base) const
|
||||
{
|
||||
return getValue(fnc, a)->getName().str();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string ConstantArgumentEntry::createName(
|
||||
llvm::Function* fnc,
|
||||
const Abi& a,
|
||||
const std::string& suffix,
|
||||
const std::string& base) const
|
||||
{
|
||||
return getValue(fnc, a)->getName().str();
|
||||
}
|
||||
|
||||
//
|
||||
//=============================================================================
|
||||
// ReturnEntry
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "retdec/utils/string.h"
|
||||
#include "retdec/bin2llvmir/optimizations/param_return/filter/filter.h"
|
||||
#include "retdec/bin2llvmir/optimizations/param_return/param_return.h"
|
||||
#define debug_enabled true
|
||||
#define debug_enabled false
|
||||
#include "retdec/bin2llvmir/utils/llvm.h"
|
||||
#include "retdec/bin2llvmir/providers/asm_instruction.h"
|
||||
#include "retdec/bin2llvmir/utils/ir_modifier.h"
|
||||
@ -115,9 +115,9 @@ bool ParamReturn::run()
|
||||
_RDA.runOnModule(*_module, _abi);
|
||||
|
||||
collectAllCalls();
|
||||
dumpInfo();
|
||||
//dumpInfo();
|
||||
filterCalls();
|
||||
dumpInfo();
|
||||
//dumpInfo();
|
||||
applyToIr();
|
||||
|
||||
_RDA.clear();
|
||||
@ -891,8 +891,16 @@ void ParamReturn::applyToIr()
|
||||
{
|
||||
for (auto& p : _fnc2calls)
|
||||
{
|
||||
// dumpInfo(p.second);
|
||||
//dumpInfo(p.second);
|
||||
//std::cout << "Applying to ir" << std::endl;
|
||||
applyToIr(p.second);
|
||||
//std::cout << "Applied!" << std::endl;
|
||||
}
|
||||
|
||||
//std::cout << "Appling to ir ref" << std::endl;
|
||||
for (auto& p : _fnc2calls)
|
||||
{
|
||||
applyToIrRef(p.second);
|
||||
}
|
||||
|
||||
for (auto& p : _fnc2calls)
|
||||
@ -902,12 +910,13 @@ void ParamReturn::applyToIr()
|
||||
}
|
||||
}
|
||||
|
||||
void ParamReturn::applyToIr(DataFlowEntry& de)
|
||||
void ParamReturn::applyToIrRef(DataFlowEntry& de)
|
||||
{
|
||||
Function* fnc = de.getFunction();
|
||||
|
||||
if (fnc == nullptr)
|
||||
{
|
||||
//std::cout << "fnc == nullptr" << std::endl;
|
||||
auto loadsOfCalls = fetchLoadsOfCalls(de.callEntries());
|
||||
|
||||
for (auto l : loadsOfCalls)
|
||||
@ -923,10 +932,10 @@ void ParamReturn::applyToIr(DataFlowEntry& de)
|
||||
return;
|
||||
}
|
||||
|
||||
auto loadsOfCalls = fetchLoadsOfCalls(de.callEntries());
|
||||
|
||||
std::map<ReturnInst*, Value*> rets2vals;
|
||||
|
||||
//std::cout << "Some analysis" << std::endl;
|
||||
|
||||
if (de.getRetValue())
|
||||
{
|
||||
if (de.getRetType() == nullptr)
|
||||
@ -952,29 +961,106 @@ void ParamReturn::applyToIr(DataFlowEntry& de)
|
||||
de.setRetType(Type::getVoidTy(_module->getContext()));
|
||||
}
|
||||
|
||||
std::vector<llvm::Value*> definitionArgs;
|
||||
for (auto& a : de.args())
|
||||
{
|
||||
if (a != nullptr)
|
||||
{
|
||||
definitionArgs.push_back(a);
|
||||
}
|
||||
}
|
||||
//std::cout << "Well here" << std::endl;
|
||||
//std::cout << de.tmpArgs.empty() << std::endl;
|
||||
//std::cout << de.loadsOfCalls.empty() << std::endl;
|
||||
//std::cout << de.rets2vals.empty() << std::endl;
|
||||
|
||||
IrModifier irm(_module, _config);
|
||||
auto* newFnc = irm.modifyFunction(
|
||||
fnc,
|
||||
de.getRetType(),
|
||||
de.argTypes(),
|
||||
de.isVariadic(),
|
||||
rets2vals,
|
||||
loadsOfCalls,
|
||||
de.getRetValue(),
|
||||
definitionArgs,
|
||||
de.argNames()).first;
|
||||
de.tmpArgs,
|
||||
rets2vals,
|
||||
de.loadsOfCalls,
|
||||
de.isVariadic()).first;
|
||||
//std::cout << "Well fuck" << std::endl;
|
||||
|
||||
//std::cout << "setting called value" << std::endl;
|
||||
de.setCalledValue(newFnc);
|
||||
}
|
||||
void ParamReturn::applyToIr(DataFlowEntry& de)
|
||||
{
|
||||
Function* fnc = de.getFunction();
|
||||
|
||||
if (fnc == nullptr)
|
||||
{
|
||||
return;
|
||||
//std::cout << "fnc == nullptr" << std::endl;
|
||||
auto loadsOfCalls = fetchLoadsOfCalls(de.callEntries());
|
||||
|
||||
for (auto l : loadsOfCalls)
|
||||
{
|
||||
IrModifier::modifyCallInst(l.first, de.getRetType(), l.second);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (fnc->arg_size() > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//std::cout << "fetching args of calls" << std::endl;
|
||||
auto loadsOfCalls = fetchArgsOfCalls(de.callEntries());
|
||||
|
||||
//std::cout << "preparing args " << std::endl;
|
||||
|
||||
auto types = de.argTypes().begin();
|
||||
auto names = de.argNames().begin();
|
||||
auto args = de.args().begin();
|
||||
|
||||
std::vector<ArgumentEntry::Ptr> definitionArgs;
|
||||
while (types != de.argTypes().end() || names != de.argNames().end() || args != de.args().end())
|
||||
{
|
||||
auto* t = types != de.argTypes().end() ?
|
||||
*(types++) : nullptr;
|
||||
auto name = names != de.argNames().end() ?
|
||||
*(names++) : "";
|
||||
auto a = args != de.args().end() ?
|
||||
*(args++) : nullptr;
|
||||
|
||||
if (a == nullptr)
|
||||
{
|
||||
definitionArgs.push_back(
|
||||
ArgumentEntry::Ptr(
|
||||
new DummyArgumentEntry(t, name)));
|
||||
}
|
||||
|
||||
if (_config->isStackVariable(a))
|
||||
{
|
||||
definitionArgs.push_back(
|
||||
ArgumentEntry::Ptr(
|
||||
new StackArgumentEntry(_config->getStackVariableOffset(a), t, name)));
|
||||
}
|
||||
else if (_abi->isRegister(a))
|
||||
{
|
||||
definitionArgs.push_back(
|
||||
ArgumentEntry::Ptr(
|
||||
new RegisterArgumentEntry(_abi->getRegisterId(a), t, name)));
|
||||
}
|
||||
}
|
||||
|
||||
de.tmpArgs = definitionArgs;
|
||||
de.loadsOfCalls = loadsOfCalls;
|
||||
|
||||
//std::cout << "it modifier called" << std::endl;
|
||||
|
||||
// IrModifier irm(_module, _config);
|
||||
// auto* newFnc = irm.modifyFunction(
|
||||
// fnc,
|
||||
// de.getRetType(),
|
||||
// de.getRetValue(),
|
||||
// definitionArgs,
|
||||
// rets2vals,
|
||||
// loadsOfCalls,
|
||||
// de.isVariadic()).first;
|
||||
|
||||
//std::cout << "setting called value" << std::endl;
|
||||
// de.setCalledValue(newFnc);
|
||||
}
|
||||
|
||||
void ParamReturn::connectWrappers(const DataFlowEntry& de)
|
||||
{
|
||||
@ -1067,11 +1153,89 @@ void ParamReturn::connectWrappers(const DataFlowEntry& de)
|
||||
}
|
||||
}
|
||||
|
||||
std::map<CallInst*, std::vector<ArgumentEntry::Ptr>> ParamReturn::fetchArgsOfCalls(
|
||||
const std::vector<CallEntry>& calls) const
|
||||
{
|
||||
std::map<CallInst*, std::vector<ArgumentEntry::Ptr>> loadsOfCalls;
|
||||
IrModifier irm(_module, _config);
|
||||
|
||||
for (auto& e : calls)
|
||||
{
|
||||
std::vector<ArgumentEntry::Ptr> loads;
|
||||
auto* call = e.getCallInstruction();
|
||||
|
||||
auto types = e.getBaseFunction()->argTypes();
|
||||
types.insert(
|
||||
types.end(),
|
||||
e.argTypes().begin(),
|
||||
e.argTypes().end());
|
||||
|
||||
auto tIt = types.begin();
|
||||
auto aIt = e.args().begin();
|
||||
|
||||
|
||||
retdec::utils::Maybe<int> nextPossibleOffset;
|
||||
while (aIt != e.args().end() || tIt != types.end())
|
||||
{
|
||||
if (_abi->isRegister(*aIt))
|
||||
{
|
||||
loads.push_back(
|
||||
ArgumentEntry::Ptr(
|
||||
new RegisterArgumentEntry(_abi->getRegisterId(*aIt), *tIt)));
|
||||
}
|
||||
else if (_config->isStackVariable(*aIt))
|
||||
{
|
||||
int stackOffset = _config->getStackVariableOffset(*aIt);
|
||||
//
|
||||
// Sometimes we do not detect stack variables duting
|
||||
// collection of values. In those cases we may
|
||||
// guess next stack variable by applying same difference
|
||||
// in stack offset as peviously found stack variable.
|
||||
//
|
||||
// Perpas better solution in those cases would be:
|
||||
// offset = previous_off+(next_off - previous_off)/2;
|
||||
//
|
||||
// Where next_offset has to be found among values.
|
||||
//
|
||||
if (!nextPossibleOffset.isUndefined())
|
||||
{
|
||||
nextPossibleOffset = nextPossibleOffset+(stackOffset-nextPossibleOffset)*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextPossibleOffset = stackOffset*2;
|
||||
}
|
||||
loads.push_back(ArgumentEntry::Ptr(
|
||||
new StackArgumentEntry(stackOffset, *tIt)));
|
||||
}
|
||||
else if (*aIt == nullptr && nextPossibleOffset.isDefined())
|
||||
{
|
||||
loads.push_back(ArgumentEntry::Ptr(
|
||||
new StackArgumentEntry(nextPossibleOffset, *tIt)));
|
||||
}
|
||||
else
|
||||
{
|
||||
loads.push_back(ArgumentEntry::Ptr(
|
||||
new DummyArgumentEntry(*tIt)));
|
||||
}
|
||||
|
||||
if (tIt != types.end())
|
||||
tIt++;
|
||||
|
||||
if (aIt != e.args().end())
|
||||
aIt++;
|
||||
}
|
||||
|
||||
loadsOfCalls[call] = std::move(loads);
|
||||
}
|
||||
|
||||
return loadsOfCalls;
|
||||
}
|
||||
|
||||
std::map<CallInst*, std::vector<Value*>> ParamReturn::fetchLoadsOfCalls(
|
||||
const std::vector<CallEntry>& calls) const
|
||||
{
|
||||
std::map<CallInst*, std::vector<Value*>> loadsOfCalls;
|
||||
IrModifier irm(_module, _config);
|
||||
|
||||
for (auto& e : calls)
|
||||
{
|
||||
@ -1095,31 +1259,19 @@ std::map<CallInst*, std::vector<Value*>> ParamReturn::fetchLoadsOfCalls(
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << llvmObjToString(*aIt) << std::endl;
|
||||
Value* l = new LoadInst(*aIt, "", call);
|
||||
|
||||
auto *t = tIt != types.end() ? *tIt++ : _abi->getDefaultType();
|
||||
|
||||
Value* conv = *aIt;
|
||||
if (auto* strType = dyn_cast<StructType>(t))
|
||||
if (tIt != types.end())
|
||||
{
|
||||
conv = irm.convertToStructure(*aIt, strType);
|
||||
}
|
||||
|
||||
if (!t->isPointerTy())
|
||||
{
|
||||
conv = IrModifier::convertValueToType(conv, PointerType::get(t, 0), call);
|
||||
auto* l = new LoadInst(t, conv);
|
||||
l->insertBefore(call);
|
||||
loads.push_back(l);
|
||||
l = IrModifier::convertValueToType(l, *tIt, call);
|
||||
tIt++;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* l = new LoadInst(conv);
|
||||
l->insertBefore(call);
|
||||
conv = IrModifier::convertValueToType(conv, PointerType::get(t, 0), call);
|
||||
loads.push_back(l);
|
||||
l = IrModifier::convertValueToType(l, _abi->getDefaultType(), call);
|
||||
}
|
||||
|
||||
loads.push_back(l);
|
||||
aIt++;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "retdec/bin2llvmir/optimizations/stack/stack.h"
|
||||
#include "retdec/bin2llvmir/providers/asm_instruction.h"
|
||||
#include "retdec/bin2llvmir/utils/ir_modifier.h"
|
||||
#define debug_enabled false
|
||||
#define debug_enabled true
|
||||
#include "retdec/bin2llvmir/utils/llvm.h"
|
||||
|
||||
using namespace llvm;
|
||||
@ -76,6 +76,8 @@ bool StackAnalysis::run()
|
||||
|
||||
for (auto& f : *_module)
|
||||
{
|
||||
std::cout << "HANDLING: " << f.getName().str() << std::endl;
|
||||
|
||||
std::map<Value*, Value*> val2val;
|
||||
for (inst_iterator I = inst_begin(f), E = inst_end(f); I != E;)
|
||||
{
|
||||
@ -96,9 +98,9 @@ bool StackAnalysis::run()
|
||||
store->getValueOperand()->getType(),
|
||||
val2val);
|
||||
|
||||
if (isa<GlobalVariable>(store->getPointerOperand()))
|
||||
if (_abi->isStackPointerRegister(store->getPointerOperand()))
|
||||
{
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
handleInstruction(
|
||||
@ -110,9 +112,9 @@ bool StackAnalysis::run()
|
||||
}
|
||||
else if (LoadInst* load = dyn_cast<LoadInst>(&i))
|
||||
{
|
||||
if (isa<GlobalVariable>(load->getPointerOperand()))
|
||||
if (_abi->isStackPointerRegister(load->getPointerOperand()))
|
||||
{
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
handleInstruction(
|
||||
@ -136,6 +138,7 @@ bool StackAnalysis::run()
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void StackAnalysis::handleInstruction(
|
||||
ReachingDefinitionsAnalysis& RDA,
|
||||
llvm::Instruction* inst,
|
||||
@ -143,17 +146,21 @@ void StackAnalysis::handleInstruction(
|
||||
llvm::Type* type,
|
||||
std::map<llvm::Value*, llvm::Value*>& val2val)
|
||||
{
|
||||
LOG << llvmObjToString(inst) << std::endl;
|
||||
LOG << "Handling instruction: " << llvmObjToString(inst) << std::endl;
|
||||
|
||||
SymbolicTree root(RDA, val, &val2val);
|
||||
LOG << root << std::endl;
|
||||
//TODO: what about all globals?
|
||||
SymbolicTree root = !_abi->isGeneralPurposeRegister(val) ?
|
||||
SymbolicTree(RDA, val, &val2val) : SymbolicTree(RDA, inst);
|
||||
|
||||
LOG << "Root of instruction: " << std::endl << root << std::endl;
|
||||
|
||||
if (!root.isVal2ValMapUsed())
|
||||
{
|
||||
bool stackPtr = false;
|
||||
for (SymbolicTree* n : root.getPostOrder())
|
||||
{
|
||||
if (_abi->isStackPointerRegister(n->value))
|
||||
if (_abi->isStackPointerRegister(n->value)
|
||||
|| _abi->isStackVariable(n->value))
|
||||
{
|
||||
stackPtr = true;
|
||||
break;
|
||||
@ -171,6 +178,7 @@ void StackAnalysis::handleInstruction(
|
||||
|
||||
auto* ci = dyn_cast_or_null<ConstantInt>(root.value);
|
||||
root.simplifyNode();
|
||||
LOG << "Simplified root of instruction: " << std::endl << root << std::endl;
|
||||
|
||||
if (auto* pdSv = getDebugStackVariable(inst->getFunction(), root))
|
||||
{
|
||||
@ -180,6 +188,7 @@ void StackAnalysis::handleInstruction(
|
||||
{
|
||||
configSv = pcSv;
|
||||
}
|
||||
LOG << "Root value: " << llvmObjToString(root.value) << std::endl;
|
||||
ci = dyn_cast_or_null<ConstantInt>(root.value);
|
||||
|
||||
if (ci == nullptr)
|
||||
@ -195,8 +204,8 @@ void StackAnalysis::handleInstruction(
|
||||
}
|
||||
}
|
||||
|
||||
LOG << "===> " << llvmObjToString(ci) << std::endl;
|
||||
LOG << "===> " << ci->getSExtValue() << std::endl;
|
||||
LOG << "\tConstant extracted: " << llvmObjToString(ci) << std::endl;
|
||||
LOG << "\tInteger constant : " << ci->getSExtValue() << std::endl;
|
||||
|
||||
std::string name = "";
|
||||
Type* t = type;
|
||||
@ -228,8 +237,8 @@ void StackAnalysis::handleInstruction(
|
||||
ca->setIsFromDebug(true);
|
||||
}
|
||||
|
||||
LOG << "===> " << llvmObjToString(a) << std::endl;
|
||||
LOG << "===> " << llvmObjToString(inst) << std::endl;
|
||||
LOG << "\tHave stack variable: " << llvmObjToString(a) << std::endl;
|
||||
LOG << "\tModifying instrucio: " << llvmObjToString(inst) << std::endl;
|
||||
LOG << std::endl;
|
||||
|
||||
auto* s = dyn_cast<StoreInst>(inst);
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/InstIterator.h>
|
||||
#include <llvm/IR/InstrTypes.h>
|
||||
|
||||
@ -241,27 +242,21 @@ Value* convertToType(
|
||||
else if (isa<LoadInst>(val) && type->isAggregateType())
|
||||
{
|
||||
conv = val;
|
||||
std::cout << "val: " << llvmObjToString(val) << std::endl;
|
||||
std::cout << "type: " << llvmObjToString(type) << std::endl;
|
||||
std::cout << "EXITTING" << std::endl;
|
||||
//std::cout << "type: " << llvmObjToString(type) << std::endl;
|
||||
//std::cout << "EXITTING" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
else if (val->getType()->isAggregateType())
|
||||
{
|
||||
std::cout << "Val: " << llvmObjToString(val) << std::endl;
|
||||
std::cout << "Type: " << llvmObjToString(type) << std::endl;
|
||||
auto* strType = dyn_cast<StructType>(val->getType());
|
||||
Instruction* gep = GetElementPtrInst::CreateInBounds(strType, val, {0}, "", before);
|
||||
gep = new LoadInst(gep);
|
||||
gep->insertBefore(before);
|
||||
conv = convertToType(gep, type, before, gep, constExpr);
|
||||
conv = gep;
|
||||
}
|
||||
else if (CompositeType* cmp = dyn_cast<CompositeType>(type))
|
||||
{
|
||||
std::cout << "The val: " << llvmObjToString(val) << std::endl;
|
||||
std::cout << "Type: " << llvmObjToString(type) << std::endl;
|
||||
//std::cout << "The val: " << llvmObjToString(val) << std::endl;
|
||||
//std::cout << "Type: " << llvmObjToString(type) << std::endl;
|
||||
assert(!isa<Instruction>(val) && "This should not happen! Please rethink convertion.");
|
||||
std::cout << "Should not happen" << std::endl;
|
||||
exit(2);
|
||||
conv = nullptr;
|
||||
}
|
||||
@ -292,8 +287,16 @@ llvm::CallInst* _modifyCallInst(
|
||||
llvm::Value* calledVal,
|
||||
llvm::ArrayRef<llvm::Value*> args)
|
||||
{
|
||||
//std::cout << "call: " << llvmObjToString(call) << std::endl;
|
||||
//std::cout << "args: " << args.size() << std::endl;
|
||||
for (auto a: args)
|
||||
{
|
||||
std::cout << "\tnarg: " << llvmObjToString(a) << std::endl;
|
||||
}
|
||||
|
||||
std::set<Instruction*> toEraseCast;
|
||||
auto* newCall = CallInst::Create(calledVal, args, "", call);
|
||||
//std::cout << "newCall: " << llvmObjToString(newCall) << std::endl;
|
||||
if (call->getNumUses())
|
||||
{
|
||||
if (!newCall->getType()->isVoidTy())
|
||||
@ -734,9 +737,8 @@ Instruction* IrModifier::getElement(llvm::Value* v, const std::vector<Value*> &i
|
||||
{
|
||||
auto* var = dyn_cast<PointerType>(v->getType());
|
||||
assert(var && "Expects variable.");
|
||||
auto* strType = dyn_cast<StructType>(var->getElementType());
|
||||
|
||||
return GetElementPtrInst::CreateInBounds(strType, v, idxs);
|
||||
return GetElementPtrInst::CreateInBounds(var->getPointerElementType(), v, idxs);
|
||||
}
|
||||
|
||||
void IrModifier::replaceElementWithStrIdx(llvm::Value* element, llvm::Value* str, std::size_t idx)
|
||||
@ -798,16 +800,9 @@ void IrModifier::replaceElementWithStrIdx(llvm::Value* element, llvm::Value* str
|
||||
auto eIdx = ConstantInt::get(IntegerType::get(_module->getContext(), 32), idx);
|
||||
|
||||
auto elem = getElement(str, {zero, eIdx});
|
||||
if (element->getType()->isArrayTy())
|
||||
elem = getElement(str, {zero, eIdx, zero});
|
||||
|
||||
|
||||
elem->insertBefore(i);
|
||||
Value* val = new LoadInst(dyn_cast<PointerType>(elem->getType())->getElementType(), elem, "", i);
|
||||
if (val->getType() != i->getType())
|
||||
val = convertValueToType(val, i->getType(), i);
|
||||
|
||||
i->replaceAllUsesWith(val);
|
||||
i->replaceAllUsesWith(convertValueToType(elem, i->getDestTy(), i));
|
||||
i->eraseFromParent();
|
||||
}
|
||||
}
|
||||
@ -1274,11 +1269,74 @@ void IrModifier::correctStackElementsInPadding(
|
||||
*/
|
||||
}
|
||||
|
||||
Value* IrModifier::convertToPointer(
|
||||
Value* obj,
|
||||
std::size_t ptrDepth)
|
||||
{
|
||||
//std::cout << "Converting to pointer: " << llvmObjToString(obj) << std::endl;
|
||||
//std::cout << "Desired pointer length: " << ptrDepth << std::endl;
|
||||
auto* ptrType = obj->getType();
|
||||
for (std::size_t i = 0; i < ptrDepth; i++)
|
||||
{
|
||||
ptrType = PointerType::get(ptrType, 0);
|
||||
}
|
||||
|
||||
std::list<User*> users;
|
||||
|
||||
// auto image = FileImageProvider::getFileImage(_module);
|
||||
auto* nobj = obj;//changeObjectDeclarationType(image, obj, ptrType);
|
||||
//std::cout << "New Object: " << llvmObjToString(nobj) << std::endl;
|
||||
|
||||
for (const auto& U : obj->users())
|
||||
{
|
||||
users.push_back(U);
|
||||
}
|
||||
|
||||
for (auto* u: users)
|
||||
{
|
||||
//std::cout << "u: " << llvmObjToString(u) << std::endl;
|
||||
auto first = ConstantInt::get(IntegerType::get(_module->getContext(), 32), ptrDepth);
|
||||
std::vector<Value*> idxs(1, first);
|
||||
|
||||
if (auto* gep = dyn_cast<GetElementPtrInst>(u))
|
||||
{
|
||||
bool first = true;
|
||||
for (auto& i : gep->indices())
|
||||
{
|
||||
if (!first)
|
||||
idxs.push_back(i.get());
|
||||
else
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
//std::cout << "using" << std::endl;
|
||||
for (auto i: idxs)
|
||||
{
|
||||
//std::cout << llvmObjToString(i) << std::endl;
|
||||
}
|
||||
|
||||
if (auto* i = dyn_cast<Instruction>(u))
|
||||
{
|
||||
auto* ni = GetElementPtrInst::CreateInBounds(obj->getType()->getPointerElementType(), nobj, idxs);
|
||||
//std::cout << "New get elem ptr: " << llvmObjToString(ni) << std::endl;
|
||||
ni->insertBefore(i);
|
||||
i->replaceAllUsesWith(ni);
|
||||
i->eraseFromParent();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false && "This should not happen!");
|
||||
}
|
||||
}
|
||||
|
||||
return nobj;
|
||||
}
|
||||
|
||||
|
||||
Value* IrModifier::convertToStructure(
|
||||
Value* obj,
|
||||
StructType* strType)
|
||||
{
|
||||
std::cout << "Correcing structure" << std::endl;
|
||||
if (auto* gv = dyn_cast<GlobalVariable>(obj))
|
||||
{
|
||||
auto addr = _config->getGlobalAddress(gv);
|
||||
@ -1287,7 +1345,6 @@ Value* IrModifier::convertToStructure(
|
||||
else if (_config->isStackVariable(obj))
|
||||
{
|
||||
auto offset = _config->getStackVariableOffset(obj);
|
||||
std::cout << "Modified opbject: " << llvmObjToString(obj) << std::endl;
|
||||
return convertToStructure(dyn_cast<AllocaInst>(obj), strType, offset);
|
||||
}
|
||||
|
||||
@ -1295,6 +1352,85 @@ Value* IrModifier::convertToStructure(
|
||||
return obj;
|
||||
}
|
||||
|
||||
Value* IrModifier::createStructureFromStacks(
|
||||
AllocaInst* startStack,
|
||||
StructType* strType,
|
||||
int offset,
|
||||
Instruction* before,
|
||||
InsertValueInst* newStructure,
|
||||
std::vector<unsigned int>idxs)
|
||||
{
|
||||
assert(_config->isStackVariable(startStack) && "Invalid usage of function!");
|
||||
|
||||
auto alignment = getAlignment(strType);
|
||||
auto padding = alignment;
|
||||
|
||||
// Create copy of local variable.
|
||||
|
||||
auto* fnc = startStack->getFunction();
|
||||
|
||||
std::size_t idx = 0;
|
||||
for (auto elem: strType->elements())
|
||||
{
|
||||
auto elemIdxs = idxs;
|
||||
elemIdxs.push_back(idx++);
|
||||
|
||||
if (auto* eStrType = dyn_cast<StructType>(elem))
|
||||
{
|
||||
auto newAlignment = getAlignment(eStrType);
|
||||
if (alignment > padding) {
|
||||
int nOffset = offset+(padding)%newAlignment;
|
||||
// TODO: find in padding
|
||||
offset = nOffset;
|
||||
}
|
||||
|
||||
padding = alignment;
|
||||
|
||||
AllocaInst* structElement = getStackVariable(fnc, offset, elem).first;
|
||||
createStructureFromStacks(structElement, eStrType, offset, before, newStructure, elemIdxs);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto a = AbiProvider::getAbi(_module);
|
||||
auto elemSize = a->getTypeByteSize(elem);
|
||||
if (padding < elemSize) {
|
||||
//TODO: search padding
|
||||
offset += padding;
|
||||
padding = alignment;
|
||||
}
|
||||
|
||||
AllocaInst* structElement = getStackVariable(fnc, offset, elem).first;
|
||||
//TODO: is this way of load/convert correct? should investigate
|
||||
Value* conv = convertValueToType(structElement, PointerType::get(elem, 0), before);
|
||||
conv = new LoadInst(elem, conv, "", before);
|
||||
|
||||
//TODO: dummy if not found
|
||||
newStructure = InsertValueInst::Create(
|
||||
newStructure ?
|
||||
static_cast<Value*>(newStructure)
|
||||
: UndefValue::get(strType),
|
||||
conv,
|
||||
elemIdxs,
|
||||
"",
|
||||
before);
|
||||
|
||||
//TODO: serach type space of primitive
|
||||
padding -= elemSize;
|
||||
offset += elemSize;
|
||||
}
|
||||
|
||||
// In case of recursive structures we must align
|
||||
// space for correct address.
|
||||
padding = padding%alignment;
|
||||
if (padding)
|
||||
{
|
||||
//TODO: search padding
|
||||
offset += padding; // (addr-oldAddr)%alignment
|
||||
}
|
||||
|
||||
return newStructure;
|
||||
}
|
||||
|
||||
llvm::GlobalVariable* IrModifier::convertToStructure(
|
||||
GlobalVariable* gv,
|
||||
StructType* strType,
|
||||
@ -1470,8 +1606,6 @@ AllocaInst* IrModifier::convertToStructure(
|
||||
// TODO:
|
||||
// following 3 linses of code can go into replaceElementWithStrIdx.
|
||||
auto* origType = structElement->getType()->getPointerElementType();
|
||||
std::cout << "Original type : " << llvmObjToString(structElement) << std::endl;
|
||||
std::cout << "Wanted type : " << llvmObjToString(elem) << std::endl;
|
||||
if (origType != elem) {
|
||||
auto* val = changeObjectDeclarationType(image, structElement, elem);
|
||||
correctUsageOfModifiedObject(structElement, val, origType);
|
||||
@ -1619,9 +1753,6 @@ void IrModifier::correctUsageOfModifiedObject(Value* val, Value* nval, Type* ori
|
||||
}
|
||||
PointerType* ptr = dyn_cast<PointerType>(dst->getType());
|
||||
assert(ptr);
|
||||
std::cout << "Before convert: " << std::endl;
|
||||
std::cout << "src " << llvmObjToString(src) << std::endl;
|
||||
std::cout << "dst " << llvmObjToString(dst) << std::endl;
|
||||
src = IrModifier::convertValueToType(src, ptr->getElementType(), store);
|
||||
store->setOperand(0, src);
|
||||
store->setOperand(1, dst);
|
||||
@ -1659,14 +1790,21 @@ void IrModifier::correctUsageOfModifiedObject(Value* val, Value* nval, Type* ori
|
||||
}
|
||||
else if (auto* gep = dyn_cast<GetElementPtrInst>(user))
|
||||
{
|
||||
//TODO: do this only if accssing first element.
|
||||
//in other cases we are totally fucked up.
|
||||
//But they will happen only if somene retarded
|
||||
//will do retarded things.
|
||||
//TODO: we should do this generally with pointers.
|
||||
|
||||
auto* conv = IrModifier::convertValueToType(nval, gep->getType(), gep);
|
||||
gep->replaceAllUsesWith(conv);
|
||||
gep->eraseFromParent();
|
||||
if (nval->getType() == PointerType::get(gep->getPointerOperandType(), 0))
|
||||
{
|
||||
auto* newLoad = new LoadInst(nval);
|
||||
newLoad->insertBefore(gep);
|
||||
|
||||
gep->setOperand(0, newLoad);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* conv = IrModifier::convertValueToType(nval, gep->getType(), gep);
|
||||
gep->replaceAllUsesWith(conv);
|
||||
gep->eraseFromParent();
|
||||
}
|
||||
}
|
||||
else if (auto* cast = dyn_cast<CastInst>(user))
|
||||
{
|
||||
@ -1688,8 +1826,6 @@ void IrModifier::correctUsageOfModifiedObject(Value* val, Value* nval, Type* ori
|
||||
else
|
||||
{
|
||||
auto* conv = IrModifier::convertValueToType(nval, cast->getType(), cast);
|
||||
std::cout << "conv: " << llvmObjToString(conv) << std::endl;
|
||||
std::cout << "cast: " << llvmObjToString(cast) << std::endl;
|
||||
if (cast != conv)
|
||||
{
|
||||
cast->replaceAllUsesWith(conv);
|
||||
@ -1710,15 +1846,11 @@ void IrModifier::correctUsageOfModifiedObject(Value* val, Value* nval, Type* ori
|
||||
auto* conv = IrModifier::convertValueToType(nval, origType, instr);
|
||||
if (val != conv)
|
||||
{
|
||||
std::cout << "val: " << llvmObjToString(val) << std::endl;
|
||||
std::cout << "conv: " << llvmObjToString(conv) << std::endl;
|
||||
|
||||
instr->replaceUsesOfWith(val, conv);
|
||||
}
|
||||
}
|
||||
else if (newConst && gvDeclr)
|
||||
{
|
||||
std::cout << "what" << std::endl;
|
||||
auto* conv = IrModifier::convertConstantToType(
|
||||
newConst,
|
||||
gvDeclr->getType()->getPointerElementType());
|
||||
@ -1731,7 +1863,6 @@ void IrModifier::correctUsageOfModifiedObject(Value* val, Value* nval, Type* ori
|
||||
//
|
||||
else if (newConst && c)
|
||||
{
|
||||
std::cout << "the funck" << std::endl;
|
||||
auto* conv = IrModifier::convertConstantToType(newConst, c->getType());
|
||||
if (c != conv)
|
||||
{
|
||||
@ -1783,7 +1914,7 @@ llvm::Value* IrModifier::changeObjectType(
|
||||
return val;
|
||||
}
|
||||
|
||||
if (val->getType() == toType)
|
||||
if (val->getType()->getPointerElementType() == toType)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
@ -1812,6 +1943,7 @@ llvm::Value* IrModifier::changeObjectType(
|
||||
return nval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inspired by ArgPromotion::DoPromotion().
|
||||
* Steps performed in ArgPromotion::DoPromotion() that are not done here:
|
||||
@ -1825,26 +1957,42 @@ llvm::Value* IrModifier::changeObjectType(
|
||||
IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
llvm::Function* fnc,
|
||||
llvm::Type* ret,
|
||||
std::vector<llvm::Type*> args,
|
||||
bool isVarArg,
|
||||
const std::map<llvm::ReturnInst*, llvm::Value*>& rets2vals,
|
||||
const std::map<llvm::CallInst*, std::vector<llvm::Value*>>& calls2vals,
|
||||
llvm::Value* retVal,
|
||||
const std::vector<llvm::Value*>& argStores,
|
||||
const std::vector<std::string>& argNames)
|
||||
const std::vector<ArgumentEntry::Ptr>& args,
|
||||
const std::map<llvm::ReturnInst*, llvm::Value*>& rets2vals,
|
||||
const std::map<llvm::CallInst*, std::vector<ArgumentEntry::Ptr>>& calls2args,
|
||||
bool isVarArg)
|
||||
{
|
||||
//std::cout << "Modifying function " << std::endl;
|
||||
//std::cout << fnc << std::endl;
|
||||
auto _abi = AbiProvider::getAbi(_module);
|
||||
//std::cout << "Her!" << std::endl;
|
||||
auto* cf = _config->getConfigFunction(fnc);
|
||||
|
||||
//std::cout << "Her!" << std::endl;
|
||||
//std::cout << ret << std::endl;
|
||||
|
||||
if (!FunctionType::isValidReturnType(ret))
|
||||
{
|
||||
{
|
||||
//std::cout << "This is bad" << std::endl;
|
||||
ret = Abi::getDefaultType(fnc->getParent());
|
||||
}
|
||||
for (Type*& t : args)
|
||||
|
||||
//std::cout << "what" << std::endl;
|
||||
std::vector<ArgumentEntry::Ptr> templArgs = args;
|
||||
//std::cout << "no copy!" << std::endl;
|
||||
if (args.empty() && !isVarArg && !calls2args.empty())
|
||||
{
|
||||
if (!FunctionType::isValidArgumentType(t))
|
||||
{
|
||||
t = Abi::getDefaultType(fnc->getParent());
|
||||
}
|
||||
//std::cout << "Suicide!" << std::endl;
|
||||
templArgs = calls2args.begin()->second;
|
||||
}
|
||||
|
||||
//std::cout << "Types:" << std::endl;
|
||||
std::vector<Type*> argTypes;
|
||||
for (auto& arg: templArgs)
|
||||
{
|
||||
//std::cout << "at: " << llvmObjToString(arg->getType(fnc, *_abi)) << std::endl;
|
||||
argTypes.push_back(arg->getType(fnc, *_abi));
|
||||
}
|
||||
|
||||
// New function type.
|
||||
@ -1852,9 +2000,11 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
ret = ret ? ret : fnc->getReturnType();
|
||||
llvm::FunctionType* newFncType = llvm::FunctionType::get(
|
||||
ret,
|
||||
args,
|
||||
argTypes,
|
||||
isVarArg);
|
||||
|
||||
//std::cout << "Created new function " << std::endl;
|
||||
|
||||
// New function.
|
||||
//
|
||||
Function *nf = nullptr;
|
||||
@ -1877,49 +2027,34 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
|
||||
// Rename arguments.
|
||||
//
|
||||
auto nIt = argNames.begin();
|
||||
auto oi = fnc->arg_begin();
|
||||
auto oie = fnc->arg_end();
|
||||
std::size_t idx = 1;
|
||||
|
||||
//std::cout << "Renaming args of new function " << std::endl;
|
||||
|
||||
std::size_t idx = 0;
|
||||
std::vector<std::string> argnames;
|
||||
for (auto i = nf->arg_begin(), e = nf->arg_end(); i != e; ++i, ++idx)
|
||||
{
|
||||
if (nIt != argNames.end() && !nIt->empty())
|
||||
llvm::Value* argValue;
|
||||
std::string argName;
|
||||
std::tie(argValue, argName) = templArgs[idx]->get(nf, *_abi, std::to_string(idx));
|
||||
|
||||
//std::cout << "New arg: " << argName << std::endl;
|
||||
|
||||
if (_abi->isStackVariable(argValue) && argValue->getName() == argName)
|
||||
{
|
||||
if (auto* st = _config->getLlvmStackVariable(nf, *nIt))
|
||||
{
|
||||
i->takeName(st);
|
||||
}
|
||||
else
|
||||
{
|
||||
i->setName(*nIt);
|
||||
}
|
||||
i->takeName(argValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (oi != oie && !oi->getName().empty())
|
||||
{
|
||||
if (nf != fnc)
|
||||
{
|
||||
i->setName(oi->getName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string n = "arg" + std::to_string(idx);
|
||||
i->setName(n);
|
||||
}
|
||||
i->setName(argName);
|
||||
|
||||
}
|
||||
|
||||
if (nIt != argNames.end())
|
||||
{
|
||||
++nIt;
|
||||
}
|
||||
if (oi != oie)
|
||||
{
|
||||
++oi;
|
||||
}
|
||||
argnames.push_back(argName);
|
||||
}
|
||||
|
||||
//std::cout << "Setting args to config function " << std::endl;
|
||||
|
||||
// Set arguments to config function.
|
||||
//
|
||||
if (cf)
|
||||
@ -1932,11 +2067,9 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
assert(!n.empty());
|
||||
auto s = retdec::config::Storage::undefined();
|
||||
retdec::config::Object arg(n, s);
|
||||
if (argNames.size() > idx)
|
||||
{
|
||||
arg.setRealName(argNames[idx]);
|
||||
arg.setIsFromDebug(true);
|
||||
}
|
||||
|
||||
arg.setRealName(argnames[idx]);
|
||||
arg.setIsFromDebug(true);
|
||||
arg.type.setLlvmIr(llvmObjToString(i->getType()));
|
||||
|
||||
// TODO: hack, we need to propagate type's wide string property.
|
||||
@ -1952,11 +2085,14 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
}
|
||||
}
|
||||
|
||||
//std::cout << "Replacing uses of old args in func body." << std::endl;
|
||||
|
||||
// Replace uses of old arguments in function body for new arguments.
|
||||
//
|
||||
for (auto i = fnc->arg_begin(), e = fnc->arg_end(), i2 = nf->arg_begin();
|
||||
i != e; ++i, ++i2)
|
||||
{
|
||||
//std::cout << "This happening?" << std::endl;
|
||||
auto* a1 = &(*i);
|
||||
auto* a2 = &(*i2);
|
||||
if (a1->getType() == a2->getType())
|
||||
@ -1974,7 +2110,6 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
auto* inst = dyn_cast<Instruction>(u);
|
||||
assert(inst && "we need an instruction here");
|
||||
|
||||
std::cout << "Is this the case?" << std::endl;
|
||||
auto* conv = IrModifier::convertValueToType(a2, a1->getType(), inst);
|
||||
inst->replaceUsesOfWith(a1, conv);
|
||||
}
|
||||
@ -1982,60 +2117,106 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
|
||||
a2->takeName(a1);
|
||||
}
|
||||
|
||||
std::cout << "Investigating function: " << nf->getName().str() << std::endl;
|
||||
//std::cout << "Finished" << std::endl;
|
||||
|
||||
// Store arguments into allocated objects (stacks, registers) at the
|
||||
// beginning of function body.
|
||||
//
|
||||
auto asIt = argStores.begin();
|
||||
auto asEndIt = argStores.end();
|
||||
for (auto aIt = nf->arg_begin(), eIt = nf->arg_end();
|
||||
aIt != eIt && asIt != asEndIt;
|
||||
++aIt, ++asIt)
|
||||
idx = 0;
|
||||
bool hasDefinitionArgs = false;
|
||||
for (auto& a: args)
|
||||
{
|
||||
auto* a = &(*aIt);
|
||||
auto* v = *asIt;
|
||||
//std::cout << "Perhaps this?" << std::endl;
|
||||
if (a->isDefined(nf, *_abi))
|
||||
{
|
||||
hasDefinitionArgs = true;
|
||||
}
|
||||
|
||||
//std::cout << "I knew it!" << std::endl;
|
||||
}
|
||||
//std::cout << "Found out that function definition is defined? " << hasDefinitionArgs << std::endl;
|
||||
//TODO: check from llvm
|
||||
|
||||
for (auto i = nf->arg_begin(), e = nf->arg_end(); hasDefinitionArgs && i != e; ++i, ++idx)
|
||||
{
|
||||
auto* v = args[idx]->getValue(nf, *_abi);
|
||||
auto* a = &(*i);
|
||||
|
||||
assert(v->getType()->isPointerTy());
|
||||
|
||||
std::cout << "Converting to structure: " << std::endl;
|
||||
std::cout << "val: " << llvmObjToString(a) << std::endl;
|
||||
std::cout << "at: " << llvmObjToString(a->getType()) << std::endl;
|
||||
std::cout << "v : " << llvmObjToString(v) << std::endl;
|
||||
std::cout << "type: " << llvmObjToString(v->getType()) << std::endl;
|
||||
auto primitiveType = a->getType();
|
||||
size_t pointerDepth = 0;
|
||||
|
||||
Value* conv = nullptr;
|
||||
if (auto* strType = dyn_cast<StructType>(a->getType()))
|
||||
while (primitiveType->isPointerTy())
|
||||
{
|
||||
v = convertToStructure(v, strType);
|
||||
primitiveType = primitiveType->getPointerElementType();
|
||||
pointerDepth++;
|
||||
}
|
||||
std::cout << "v : " << llvmObjToString(v) << std::endl;
|
||||
|
||||
conv = IrModifier::convertValueToType(
|
||||
a,
|
||||
v->getType()->getPointerElementType(),
|
||||
&nf->front().front());
|
||||
std::cout << "Converting to primitive" << std::endl;
|
||||
|
||||
auto* s = new StoreInst(conv, v);
|
||||
//TODO: do not change dewclaration if -> declaration
|
||||
Value* conv = v;
|
||||
Value* aconv = a;
|
||||
|
||||
if (auto* alloca = dyn_cast<AllocaInst>(v))
|
||||
if (_config->isStackVariable(conv))
|
||||
{
|
||||
if (auto* strType = dyn_cast<StructType>(primitiveType))
|
||||
{
|
||||
//std::cout << "Converting to structure" << std::endl;
|
||||
conv = convertToStructure(v, strType);
|
||||
}
|
||||
else
|
||||
{
|
||||
conv = changeObjectType(
|
||||
FileImageProvider::getFileImage(_module),
|
||||
v,
|
||||
primitiveType);
|
||||
}
|
||||
|
||||
std::cout << "Convering to type" << std::endl;
|
||||
|
||||
//std::cout << "Vhangeing objet type: " << std::endl;
|
||||
conv = changeObjectType(
|
||||
FileImageProvider::getFileImage(_module),
|
||||
conv,
|
||||
a->getType());
|
||||
std::cout << "Generatinbg store" << std::endl;
|
||||
|
||||
std::cout << "Well conv := " << llvmObjToString(conv) << std::endl;
|
||||
std::cout << "Should be pointer of " << llvmObjToString(a) << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
aconv = convertValueToType(a, conv->getType()->getPointerElementType(), &nf->front().front());
|
||||
}
|
||||
|
||||
|
||||
auto* s = new StoreInst(aconv, conv);
|
||||
|
||||
std::cout << "generated" << std::endl;
|
||||
|
||||
if (auto* alloca = dyn_cast<AllocaInst>(conv))
|
||||
{
|
||||
s->insertAfter(alloca);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (conv == a)
|
||||
if (a == aconv)
|
||||
{
|
||||
s->insertBefore(&nf->front().front());
|
||||
}
|
||||
else
|
||||
{
|
||||
s->insertAfter(cast<Instruction>(conv));
|
||||
s->insertAfter(cast<Instruction>(aconv));
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Done1" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Updating returns" << std::endl;
|
||||
|
||||
// Update returns in function body.
|
||||
//
|
||||
// if (nf->getReturnType() != fnc->getReturnType())
|
||||
@ -2091,7 +2272,51 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "HERE" << std::endl;
|
||||
std::cout << "Preparing calls" << nf->getName().str() << std::endl;
|
||||
std::map<CallInst*, std::vector<Value*>> preparedCalls;
|
||||
// Alter calls
|
||||
for (auto ce: calls2args)
|
||||
{
|
||||
CallInst* call = ce.first;
|
||||
std::vector<Value*> args;
|
||||
for (auto& arg: ce.second)
|
||||
{
|
||||
Value* v; Type* t;
|
||||
std::tie(v, t) = arg->get(call->getFunction(), *_abi);
|
||||
Value* conv = v;
|
||||
std::cout << "\tObject passed as arg: " << llvmObjToString(conv) << std::endl;
|
||||
|
||||
auto* strType = dyn_cast<StructType>(t);
|
||||
if (strType && _config->isStackVariable(v))
|
||||
{
|
||||
conv = createStructureFromStacks(
|
||||
dyn_cast<AllocaInst>(conv),
|
||||
strType,
|
||||
_config->getStackVariableOffset(conv),
|
||||
call);
|
||||
}
|
||||
else if (!t->isPointerTy())
|
||||
{
|
||||
conv = IrModifier::convertValueToType(conv, PointerType::get(t, 0), call);
|
||||
auto* l = new LoadInst(t, conv);
|
||||
l->insertBefore(call);
|
||||
conv = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* l = new LoadInst(conv);
|
||||
l->insertBefore(call);
|
||||
conv = IrModifier::convertValueToType(l, t, call);
|
||||
}
|
||||
std::cout << "\tObject passed as arg: " << llvmObjToString(conv) << std::endl;
|
||||
args.push_back(conv);
|
||||
}
|
||||
|
||||
preparedCalls[call] = args;
|
||||
}
|
||||
|
||||
//std::cout << "Preparing other users" << std::endl;
|
||||
|
||||
// Update function users (calls, etc.).
|
||||
//
|
||||
auto uIt = fnc->user_begin();
|
||||
@ -2102,55 +2327,9 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
|
||||
if (CallInst* call = dyn_cast<CallInst>(u))
|
||||
{
|
||||
std::vector<Value*> args;
|
||||
|
||||
auto fIt = calls2vals.find(call);
|
||||
if (fIt != calls2vals.end())
|
||||
if (!calls2args.count(call))
|
||||
{
|
||||
auto vIt = fIt->second.begin();
|
||||
for (auto fa = nf->arg_begin(); fa != nf->arg_end(); ++fa)
|
||||
{
|
||||
std::cout << "fa: " << llvmObjToString(fa) << std::endl;
|
||||
if (vIt != fIt->second.end())
|
||||
{
|
||||
Value* conv = nullptr;
|
||||
if (auto* strType = dyn_cast<StructType>(fa->getType()))
|
||||
{
|
||||
std::cout << "vItStr: " << llvmObjToString(*vIt) << std::endl;
|
||||
conv = convertToStructure(*vIt, strType);
|
||||
std::cout << "vItStr: " << llvmObjToString(*vIt) << std::endl;
|
||||
std::cout << "DONE" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "vIt: " << llvmObjToString(*vIt) << std::endl;
|
||||
conv = IrModifier::convertValueToType(
|
||||
*vIt,
|
||||
fa->getType(),
|
||||
call);
|
||||
}
|
||||
args.push_back(conv);
|
||||
++vIt;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* conv = IrModifier::convertValueToType(
|
||||
_config->getGlobalDummy(),
|
||||
fa->getType(),
|
||||
call);
|
||||
args.push_back(conv);
|
||||
}
|
||||
}
|
||||
std::cout << "Ok?" << std::endl;
|
||||
while (isVarArg && vIt != fIt->second.end())
|
||||
{
|
||||
args.push_back(*vIt);
|
||||
++vIt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "PLS" << std::endl;
|
||||
std::vector<Value*> args;
|
||||
unsigned ai = 0;
|
||||
unsigned ae = call->getNumArgOperands();
|
||||
for (auto fa = nf->arg_begin(); fa != nf->arg_end(); ++fa)
|
||||
@ -2173,23 +2352,7 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
args.push_back(conv);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(isVarArg || args.size() == nf->arg_size());
|
||||
|
||||
auto* nc = _modifyCallInst(
|
||||
call,
|
||||
nf,
|
||||
args);
|
||||
|
||||
if (!ret->isVoidTy() && retVal)
|
||||
{
|
||||
auto* n = nc->getNextNode();
|
||||
assert(n);
|
||||
auto* conv = IrModifier::convertValueToType(
|
||||
nc,
|
||||
retVal->getType()->getPointerElementType(),
|
||||
n);
|
||||
new StoreInst(conv, retVal, n);
|
||||
preparedCalls[call] = args;
|
||||
}
|
||||
}
|
||||
else if (StoreInst* s = dyn_cast<StoreInst>(u))
|
||||
@ -2214,7 +2377,35 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
assert(false && "unhandled use");
|
||||
}
|
||||
}
|
||||
std::cout << "OLALAL" << std::endl;
|
||||
|
||||
//std::cout << "Modifing calls and other users" << std::endl;
|
||||
|
||||
for (auto cv: preparedCalls)
|
||||
{
|
||||
CallInst* call = cv.first;
|
||||
|
||||
//std::cout << "Modifying call" << std::endl;
|
||||
|
||||
auto* nc = _modifyCallInst(
|
||||
call,
|
||||
nf,
|
||||
cv.second);
|
||||
|
||||
//std::cout << "Setting return" << std::endl;
|
||||
|
||||
if (!ret->isVoidTy() && retVal)
|
||||
{
|
||||
auto* n = nc->getNextNode();
|
||||
assert(n);
|
||||
auto* conv = IrModifier::convertValueToType(
|
||||
nc,
|
||||
retVal->getType()->getPointerElementType(),
|
||||
n);
|
||||
new StoreInst(conv, retVal, n);
|
||||
}
|
||||
}
|
||||
|
||||
//std::cout << "Changing ret type" << std::endl;
|
||||
|
||||
if (nf->getType() != fnc->getType())
|
||||
{
|
||||
@ -2226,6 +2417,7 @@ IrModifier::FunctionPair IrModifier::modifyFunction(
|
||||
// No ide why.
|
||||
// fnc->eraseFromParent();
|
||||
|
||||
//std::cout << "All ok!" << std::endl;
|
||||
return {nf, cf};
|
||||
}
|
||||
|
||||
@ -2238,12 +2430,15 @@ llvm::Argument* IrModifier::modifyFunctionArgumentType(
|
||||
llvm::Type* type)
|
||||
{
|
||||
auto* f = arg->getParent();
|
||||
std::vector<Type*> args;
|
||||
std::vector<ArgumentEntry::Ptr> args;
|
||||
std::size_t idx = 0;
|
||||
for (auto& a : f->args())
|
||||
{
|
||||
args.push_back(&a == arg ? type : a.getType());
|
||||
args.push_back(ArgumentEntry::Ptr(
|
||||
new FunctionArgumentEntry(idx, &a == arg ? type : a.getType())));
|
||||
idx++;
|
||||
}
|
||||
auto* nf = modifyFunction(f, f->getReturnType(), args).first;
|
||||
auto* nf = modifyFunction(f, f->getReturnType(), nullptr, args).first;
|
||||
std::size_t i = 0;
|
||||
for (auto& a : nf->args())
|
||||
{
|
||||
|
@ -79,8 +79,7 @@ TEST_F(IrModifierTests, convertValueToTypeFunctionToPointer)
|
||||
parseInput(R"(
|
||||
declare void @import()
|
||||
define void @fnc() {
|
||||
ret void
|
||||
}
|
||||
ret void1`` }
|
||||
)");
|
||||
auto* import = getValueByName("import");
|
||||
auto* r = getNthInstruction<ReturnInst>();
|
||||
@ -305,16 +304,20 @@ TEST_F(IrModifierTests, modifyFunctionVoid)
|
||||
auto* call2 = getNthInstruction<CallInst>(1);
|
||||
|
||||
auto* i32 = Type::getInt32Ty(context);
|
||||
auto* a1 = ConstantInt::get(i32, 123);
|
||||
auto* a2 = ConstantInt::get(i32, 456);
|
||||
auto a1 = ArgumentEntry::Ptr(new ConstantArgumentEntry(
|
||||
dyn_cast<Constant>(ConstantInt::get(i32, 123)),
|
||||
i32));
|
||||
auto a2 = ArgumentEntry::Ptr(new ConstantArgumentEntry(
|
||||
dyn_cast<Constant>(ConstantInt::get(i32, 456)),
|
||||
i32));
|
||||
|
||||
auto c = Config::empty(module.get());
|
||||
IrModifier irm(module.get(), &c);
|
||||
irm.modifyFunction(
|
||||
import,
|
||||
i32,
|
||||
{i32},
|
||||
false,
|
||||
nullptr,
|
||||
{},
|
||||
std::map<ReturnInst*, Value*>(),
|
||||
{{call1, {a1}}, {call2, {a2}}});
|
||||
|
||||
@ -352,8 +355,12 @@ TEST_F(IrModifierTests, modifyFunctionWithZeroArguments)
|
||||
auto* call2 = getNthInstruction<CallInst>(1);
|
||||
auto* ret = getNthInstruction<ReturnInst>();
|
||||
auto* i32 = Type::getInt32Ty(context);
|
||||
auto* a1 = ConstantInt::get(i32, 123);
|
||||
auto* a2 = ConstantInt::get(i32, 456);
|
||||
auto a1 = ArgumentEntry::Ptr(new ConstantArgumentEntry(
|
||||
dyn_cast<Constant>(ConstantInt::get(i32, 123)),
|
||||
i32));
|
||||
auto a2 = ArgumentEntry::Ptr(new ConstantArgumentEntry(
|
||||
dyn_cast<Constant>(ConstantInt::get(i32, 456)),
|
||||
i32));
|
||||
auto* r = ConstantInt::get(i32, 789);
|
||||
auto* userDef = cast<Function>(getValueByName("userDef"));
|
||||
|
||||
@ -362,8 +369,8 @@ TEST_F(IrModifierTests, modifyFunctionWithZeroArguments)
|
||||
irm.modifyFunction(
|
||||
userDef,
|
||||
i32,
|
||||
{i32},
|
||||
false,
|
||||
nullptr,
|
||||
{},
|
||||
{{ret, r}},
|
||||
{{call1, {a1}}, {call2, {a2}}});
|
||||
|
||||
@ -407,7 +414,11 @@ TEST_F(IrModifierTests, modifyFunctionWithExistingArguments)
|
||||
auto* d = Type::getDoubleTy(context);
|
||||
auto c = Config::empty(module.get());
|
||||
IrModifier irm(module.get(), &c);
|
||||
irm.modifyFunction(fnc, f, {f, i32, d});
|
||||
//TODO: provide separate function for this.
|
||||
auto df = ArgumentEntry::Ptr(new DummyArgumentEntry(f));
|
||||
auto dd = ArgumentEntry::Ptr(new DummyArgumentEntry(d));
|
||||
auto di = ArgumentEntry::Ptr(new DummyArgumentEntry(i32));
|
||||
irm.modifyFunction(fnc, f, nullptr, {df, di, dd});
|
||||
|
||||
std::string exp = R"(
|
||||
define float @fnc(float %a1, i32 %a2, double %a3) {
|
||||
@ -452,22 +463,27 @@ TEST_F(IrModifierTests, modifyFunctionVariadic)
|
||||
ret i32 0
|
||||
}
|
||||
)");
|
||||
|
||||
auto* fnc = cast<Function>(getValueByName("fnc"));
|
||||
auto* c1 = getNthInstruction<CallInst>();
|
||||
auto* c2 = getNthInstruction<CallInst>(1);
|
||||
auto* ret = getNthInstruction<ReturnInst>();
|
||||
auto* i32 = Type::getInt32Ty(context);
|
||||
auto* ci = ConstantInt::get(i32, 0);
|
||||
auto ci = ArgumentEntry::Ptr(new ConstantArgumentEntry(
|
||||
dyn_cast<Constant>(ConstantInt::get(i32, 0)),
|
||||
i32));
|
||||
auto ap = ArgumentEntry::Ptr(new DummyArgumentEntry(i32));
|
||||
|
||||
auto c = Config::empty(module.get());
|
||||
IrModifier irm(module.get(), &c);
|
||||
irm.modifyFunction(
|
||||
fnc,
|
||||
i32,
|
||||
{i32},
|
||||
true,
|
||||
{{ret, ci}},
|
||||
{{c1, {ci, ci}}, {c2, {ci, ci, ci, ci}}});
|
||||
nullptr,
|
||||
{ap},
|
||||
{{ret, ConstantInt::get(i32, 0)}},
|
||||
{{c1, {ci, ci}}, {c2, {ci, ci, ci, ci}}},
|
||||
true);
|
||||
|
||||
std::string exp = R"(
|
||||
target datalayout = "e-p:32:32:32-f80:32:32"
|
||||
|
Loading…
x
Reference in New Issue
Block a user