mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Add CPUStateAccessAnalysisPass
This commit adds a new analysis pass: `CPUStateAccessAnalysisPass`.
This pass currently performs 4 operations.
1. A preliminary analysis of the call graph, to select the functions
that are reachable from the root function through direct calls. All
the other performed operations are executed on this set of reachable
functions.
2. An interprocedural forward taint analysis, starting from the uses of
`env`, the global variable pointing to the QEMU struct continaint the
CPU. This analysis taints all the instructions that use the address
of `env`, until a load or a store is met. If a load or a store uses a
tainted Value as address it means that it is accessing a CSV at a
given offset (which at this point is still unknown).
3. An interprocedural offset analysis, which deduces the possible
offsets used by every tainted load/store to access the CSV. This
analysis initially works backwards, exploring all the Values that
contribute at the computation of the addresses used by tainted
load/stores. Once it finds all the sources, it starts propagating the
values forward, collecting the offsets computed along the way. It
does this until it reaches the tainted load/stores again. At that
point the analysis knows all the possible offsets used by each
tainted load/store to access the CPU state.
4. The results of the previous steps are used to do 3 things:
* marking all the indirect calls with tainted arguments as illegal;
this is necessary because those calls may access the CPU State in
unpredictable ways;
* attaching metadata to all the call sites to QEMU helpers in the root
function; these metadata provide information on which parts of the
CPU State may be accessed from that call site, which is a
potentially useful information for users of libtinycode that we also
plan to use in other parts of revamb;
* substituting loads, stores, and memcpys to and from the CPU state
with accesses to global variables; this operation effectively
replaces what was previously done by the CorrectCPUStateUsagePass,
which is now obsolete and was removed in this commit.
This commit is contained in:
committed by
Alessandro Di Federico
parent
83992ba4c3
commit
f90f9451fa
+73
-416
@@ -72,402 +72,6 @@ private:
|
||||
std::vector<OffsetValuePair> Stack;
|
||||
};
|
||||
|
||||
static const int64_t ErrorOffset = std::numeric_limits<int64_t>::max();
|
||||
|
||||
bool CorrectCPUStateUsagePass::runOnModule(Module& TheModule) {
|
||||
OffsetValueStack WorkList;
|
||||
|
||||
Value *CPUStatePtr = TheModule.getGlobalVariable("env");
|
||||
|
||||
// Do we even have "env"?
|
||||
if (CPUStatePtr == nullptr)
|
||||
return false;
|
||||
|
||||
assert(CPUStatePtr->getType()->isPointerTy());
|
||||
|
||||
struct Specialization {
|
||||
Function *F;
|
||||
Function *Original;
|
||||
std::vector<std::pair<unsigned, int64_t>> SpecializedArgs;
|
||||
};
|
||||
|
||||
std::vector<Specialization> Specializations;
|
||||
std::map<Function *, int64_t> OffsetFunctions;
|
||||
|
||||
const DataLayout& DL = TheModule.getDataLayout();
|
||||
|
||||
while (true) {
|
||||
if (WorkList.empty()) {
|
||||
for (Use& CPUStateUse : CPUStatePtr->uses()) {
|
||||
auto *Load = cast<LoadInst>(CPUStateUse.getUser());
|
||||
assert(Load->getPointerOperand() == CPUStatePtr);
|
||||
|
||||
WorkList.pushIfNew(Variables->EnvOffset, Load);
|
||||
}
|
||||
}
|
||||
|
||||
if (WorkList.empty())
|
||||
break;
|
||||
|
||||
|
||||
int64_t CurrentOffset;
|
||||
Value *CurrentValue;
|
||||
std::tie(CurrentOffset, CurrentValue) = WorkList.pop();
|
||||
|
||||
std::vector<std::tuple<User *, Value *, Value *>> Replacements;
|
||||
|
||||
for (Use& TheUse : CurrentValue->uses()) {
|
||||
Instruction *TheUser = cast<Instruction>(TheUse.getUser());
|
||||
auto Opcode = TheUser->getOpcode();
|
||||
|
||||
if (CurrentOffset == ErrorOffset
|
||||
&& Opcode != Instruction::Load
|
||||
&& Opcode != Instruction::Store) {
|
||||
// Not loading or storing, propagate the error value
|
||||
WorkList.push(ErrorOffset, TheUser);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(Opcode) {
|
||||
case Instruction::Load:
|
||||
case Instruction::Store:
|
||||
{
|
||||
auto *Load = dyn_cast<LoadInst>(TheUser);
|
||||
auto *Store = dyn_cast<StoreInst>(TheUser);
|
||||
|
||||
IRBuilder<> Builder(cast<Instruction>(TheUser));
|
||||
|
||||
bool Success = false;
|
||||
if (Load != nullptr) {
|
||||
unsigned Size = DL.getTypeAllocSize(TheUser->getType());
|
||||
assert(Size != 0);
|
||||
|
||||
unsigned CurrentEnvOffset = CurrentOffset - EnvOffset;
|
||||
auto *Loaded = Variables->loadFromEnvOffset(Builder,
|
||||
Size,
|
||||
CurrentEnvOffset);
|
||||
Success = Loaded != nullptr;
|
||||
if (Success)
|
||||
TheUser->replaceAllUsesWith(Loaded);
|
||||
} else {
|
||||
Value *ToStore = Store->getValueOperand();
|
||||
unsigned Size = DL.getTypeAllocSize(ToStore->getType());
|
||||
assert(Size != 0);
|
||||
|
||||
unsigned CurrentEnvOffset = CurrentOffset - EnvOffset;
|
||||
Success = Variables->storeToEnvOffset(Builder,
|
||||
Size,
|
||||
CurrentEnvOffset,
|
||||
ToStore);
|
||||
}
|
||||
|
||||
if (Success)
|
||||
Replacements.push_back(std::make_tuple(TheUser, nullptr, nullptr));
|
||||
else
|
||||
Builder.CreateCall(TheModule.getFunction("abort"));
|
||||
|
||||
break;
|
||||
}
|
||||
case Instruction::IntToPtr:
|
||||
case Instruction::BitCast:
|
||||
{
|
||||
// A bitcast, just propagate it
|
||||
WorkList.push(CurrentOffset, TheUser);
|
||||
break;
|
||||
}
|
||||
case Instruction::GetElementPtr:
|
||||
{
|
||||
// A GEP requires to update the offset
|
||||
auto *GEP = cast<GetElementPtrInst>(TheUser);
|
||||
unsigned AS = GEP->getPointerAddressSpace();
|
||||
APInt APOffset(DL.getPointerSizeInBits(AS), 0, true);
|
||||
bool Result = GEP->accumulateConstantOffset(DL, APOffset);
|
||||
|
||||
// TODO: do some kind of warning reporting here
|
||||
// TODO: split the basic block and add an unreachable here
|
||||
if (!Result) {
|
||||
CallInst::Create(TheModule.getFunction("abort"), { }, GEP);
|
||||
continue;
|
||||
}
|
||||
|
||||
int64_t NewOffset = APOffset.getSExtValue();
|
||||
WorkList.push(CurrentOffset + NewOffset, TheUser);
|
||||
break;
|
||||
}
|
||||
case Instruction::Add:
|
||||
{
|
||||
unsigned OtherOperandIndex = 1 - TheUse.getOperandNo();
|
||||
Value *OtherOperand = TheUser->getOperand(OtherOperandIndex);
|
||||
|
||||
if (!isa<ConstantInt>(OtherOperand)) {
|
||||
auto *InvalidInst = cast<Instruction>(TheUser);
|
||||
CallInst::Create(TheModule.getFunction("abort"), { }, InvalidInst);
|
||||
continue;
|
||||
}
|
||||
|
||||
int64_t Addend = cast<ConstantInt>(OtherOperand)->getSExtValue();
|
||||
WorkList.push(CurrentOffset + Addend, TheUser);
|
||||
break;
|
||||
}
|
||||
case Instruction::Call:
|
||||
{
|
||||
auto *Call = cast<CallInst>(TheUser);
|
||||
Function *Callee = Call->getCalledFunction();
|
||||
|
||||
// Some casting with constant expressions?
|
||||
if (Callee == nullptr) {
|
||||
if (auto *Cast = dyn_cast<ConstantExpr>(Call->getCalledValue())) {
|
||||
assert(Cast->getOpcode() == Instruction::BitCast);
|
||||
Callee = cast<Function>(Cast->getOperand(0));
|
||||
}
|
||||
}
|
||||
|
||||
if (Callee != nullptr
|
||||
&& Callee->getIntrinsicID() == Intrinsic::dbg_declare)
|
||||
continue;
|
||||
|
||||
// We only support memcpys where the last parameter is constant
|
||||
if (Callee == nullptr
|
||||
|| (Callee->getIntrinsicID() == Intrinsic::memcpy
|
||||
&& !isa<ConstantInt>(Call->getArgOperand(2)))) {
|
||||
auto *InvalidInst = cast<Instruction>(TheUser);
|
||||
CallInst::Create(TheModule.getFunction("abort"), { }, InvalidInst);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We're memcpy'ing to the env
|
||||
if (Callee->getIntrinsicID() == Intrinsic::memcpy) {
|
||||
IRBuilder<> Builder(TheModule.getContext());
|
||||
Builder.SetInsertPoint(Call);
|
||||
|
||||
unsigned EnvOpIndex = (Call->getArgOperand(0) == CurrentValue ?
|
||||
0 : 1);
|
||||
Value *BaseOp = Call->getArgOperand(1 - EnvOpIndex);
|
||||
auto *ValueOp = cast<Constant>(Call->getArgOperand(2));
|
||||
Value *BasePtr = Builder.CreatePtrToInt(BaseOp,
|
||||
Builder.getInt64Ty());
|
||||
|
||||
uint64_t TotalSize = getZExtValue(ValueOp, DL);
|
||||
uint64_t Offset = 0;
|
||||
|
||||
while (Offset < TotalSize) {
|
||||
GlobalVariable *Var = nullptr;
|
||||
Var = Variables->getByCPUStateOffset(CurrentOffset + Offset);
|
||||
|
||||
// Consider the case when there's simply nothing there (alignment
|
||||
// space)
|
||||
if (Var == nullptr) {
|
||||
Offset++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Type *PointeeTy = Var->getType()->getPointerElementType();
|
||||
uint64_t Size = DL.getTypeAllocSize(PointeeTy);
|
||||
|
||||
Value *Address = Builder.CreateAdd(Builder.getInt64(Offset),
|
||||
BasePtr);
|
||||
Value *Ptr = Builder.CreateIntToPtr(Address, Var->getType());
|
||||
|
||||
if (EnvOpIndex == 0)
|
||||
Builder.CreateStore(Builder.CreateLoad(Ptr), Var);
|
||||
else
|
||||
Builder.CreateStore(Builder.CreateLoad(Var), Ptr);
|
||||
|
||||
Offset += Size;
|
||||
}
|
||||
|
||||
if (Offset != TotalSize) {
|
||||
auto *InvalidInstruction = cast<Instruction>(TheUser);
|
||||
CallInst::Create(TheModule.getFunction("abort"),
|
||||
{ },
|
||||
InvalidInstruction);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set memcpy size to 0
|
||||
auto *Zero = ConstantInt::get(Call->getArgOperand(2)->getType(), 0);
|
||||
Call->setArgOperand(2, Zero);
|
||||
continue;
|
||||
}
|
||||
|
||||
assert((Callee->getName().startswith("helper")
|
||||
|| !Callee->empty())
|
||||
&& "external functions are not supported");
|
||||
|
||||
if (Callee->empty())
|
||||
break;
|
||||
|
||||
// TODO: move all the specialization-handling code outside
|
||||
// Is the callee already a specialization?
|
||||
auto Comparison = [&Callee] (Specialization &S) {
|
||||
return S.F == Callee;
|
||||
};
|
||||
auto CurrentSpecialization = std::find_if(Specializations.begin(),
|
||||
Specializations.end(),
|
||||
Comparison);
|
||||
|
||||
Function *Original = Callee;
|
||||
std::vector<std::pair<unsigned, int64_t>> SpecializedArgs;
|
||||
|
||||
// If the callee was already a specialization, preserve its
|
||||
// specialized arguments
|
||||
if (CurrentSpecialization != Specializations.end()) {
|
||||
|
||||
// Check if we're good with this specialization
|
||||
bool SpecializationMatches = false;
|
||||
for (auto &P : CurrentSpecialization->SpecializedArgs) {
|
||||
if (P.first == TheUse.getOperandNo()) {
|
||||
assert(P.second == CurrentOffset);
|
||||
SpecializationMatches = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (SpecializationMatches)
|
||||
continue;
|
||||
|
||||
Original = CurrentSpecialization->Original;
|
||||
SpecializedArgs = CurrentSpecialization->SpecializedArgs;
|
||||
}
|
||||
|
||||
// Add the new argument to specialize
|
||||
SpecializedArgs.push_back({ TheUse.getOperandNo(), CurrentOffset });
|
||||
|
||||
// Does the specialization we want already exists?
|
||||
Specialization *Matching = nullptr;
|
||||
for (Specialization &S : Specializations) {
|
||||
if (S.Original == Original
|
||||
&& S.SpecializedArgs.size() == SpecializedArgs.size()) {
|
||||
|
||||
Matching = &S;
|
||||
for (std::pair<unsigned, int64_t> A : SpecializedArgs) {
|
||||
|
||||
bool Found = false;
|
||||
for (std::pair<unsigned, int64_t> B : S.SpecializedArgs) {
|
||||
if (A.first == B.first && A.second == B.second) {
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!Found) {
|
||||
Matching = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Matching != nullptr)
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (Matching == nullptr) {
|
||||
// We need a new specialization
|
||||
ValueToValueMapTy VTV;
|
||||
SmallVector<ReturnInst *, 5> Returns;
|
||||
|
||||
// Clone existing function
|
||||
std::stringstream NewName;
|
||||
NewName << Callee->getName().str() << "_" << Specializations.size();
|
||||
Callee->setLinkage(GlobalValue::InternalLinkage);
|
||||
Function *NewFunc = Function::Create(Callee->getFunctionType(),
|
||||
GlobalValue::InternalLinkage,
|
||||
NewName.str(),
|
||||
Callee->getParent());
|
||||
|
||||
unsigned I = 0;
|
||||
auto CalleeArg = Callee->arg_begin();
|
||||
auto NewArg = NewFunc->arg_begin();
|
||||
for (CalleeArg = Callee->arg_begin();
|
||||
CalleeArg != Callee->arg_end();
|
||||
CalleeArg++) {
|
||||
NewArg->setName(CalleeArg->getName());
|
||||
|
||||
WorkList.cloneSisters(&*CalleeArg, &*NewArg);
|
||||
|
||||
VTV[&*CalleeArg] = &*NewArg++;
|
||||
}
|
||||
|
||||
CloneFunctionInto(NewFunc, Callee, VTV, true, Returns);
|
||||
|
||||
Specialization New;
|
||||
New.F = NewFunc;
|
||||
New.Original = Original;
|
||||
New.SpecializedArgs = SpecializedArgs;
|
||||
Specializations.push_back(New);
|
||||
Matching = &Specializations.back();
|
||||
|
||||
// The function is new, we have to explore its argument usage
|
||||
|
||||
// Find the corresponding argument
|
||||
auto ArgsI = NewFunc->arg_begin();
|
||||
|
||||
for (I = 0;
|
||||
I < Call->getNumArgOperands() && ArgsI != NewFunc->arg_end();
|
||||
I++, ArgsI++) {
|
||||
Use& ArgUse = Call->getArgOperandUse(I);
|
||||
if (ArgUse.getOperandNo() == TheUse.getOperandNo())
|
||||
break;
|
||||
}
|
||||
assert(I < Call->getNumArgOperands()
|
||||
&& ArgsI != NewFunc->arg_end());
|
||||
|
||||
Value *TargetArg = static_cast<Value *>(&*ArgsI);
|
||||
|
||||
if (TargetArg->use_begin() != TargetArg->use_end()) {
|
||||
assert(!NewFunc->isVarArg());
|
||||
|
||||
// If not already considered, enqueue the argument to the worklist
|
||||
WorkList.pushIfNew(CurrentOffset, TargetArg);
|
||||
}
|
||||
}
|
||||
|
||||
auto It = OffsetFunctions.find(Matching->F);
|
||||
if (It != OffsetFunctions.end())
|
||||
WorkList.push(It->second, static_cast<Value *>(Call));
|
||||
|
||||
auto *OriginalCalleeTy = Call->getCalledValue()->getType();
|
||||
Call->setCalledFunction(ConstantExpr::getBitCast(Matching->F,
|
||||
OriginalCalleeTy));
|
||||
|
||||
break;
|
||||
}
|
||||
case Instruction::Ret:
|
||||
{
|
||||
// This function returns a pointer to the state
|
||||
Function *CurrentFunction = TheUser->getParent()->getParent();
|
||||
OffsetFunctions[CurrentFunction] = CurrentOffset;
|
||||
for (User *FunctionUse : CurrentFunction->users()) {
|
||||
auto Call = cast<CallInst>(FunctionUse);
|
||||
assert(Call->getCalledFunction() == CurrentFunction);
|
||||
WorkList.pushIfNew(CurrentOffset, static_cast<Value *>(Call));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Unhandled situation, propagate an error value until the next load
|
||||
WorkList.push(ErrorOffset, TheUser);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto Replacement : Replacements)
|
||||
if (std::get<1>(Replacement) == nullptr)
|
||||
cast<Instruction>(std::get<0>(Replacement))->eraseFromParent();
|
||||
else
|
||||
std::get<0>(Replacement)->replaceUsesOfWith(std::get<1>(Replacement),
|
||||
std::get<2>(Replacement));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char CorrectCPUStateUsagePass::ID = 0;
|
||||
|
||||
static RegisterPass<CorrectCPUStateUsagePass> X("correct-cpustate-usage",
|
||||
"Correct CPUState Usage Pass",
|
||||
false,
|
||||
false);
|
||||
|
||||
static std::pair<IntegerType *, unsigned>
|
||||
getTypeAtOffset(const DataLayout *TheLayout, Type *VarType, intptr_t Offset) {
|
||||
unsigned Depth = 0;
|
||||
@@ -529,7 +133,7 @@ getTypeAtOffset(const DataLayout *TheLayout, Type *VarType, intptr_t Offset) {
|
||||
<< "\n");
|
||||
|
||||
if (Offset >= FieldEnd)
|
||||
return { nullptr, 0 };
|
||||
return { nullptr, 0 }; // It's padding
|
||||
|
||||
Offset -= FieldOffset;
|
||||
}
|
||||
@@ -655,8 +259,6 @@ bool VariableManager::storeToCPUStateOffset(IRBuilder<> &Builder,
|
||||
unsigned Remaining;
|
||||
std::tie(Target, Remaining) = getByCPUStateOffsetInternal(Offset);
|
||||
|
||||
assert(Target != nullptr);
|
||||
|
||||
if (Target == nullptr)
|
||||
return false;
|
||||
|
||||
@@ -684,16 +286,19 @@ bool VariableManager::storeToCPUStateOffset(IRBuilder<> &Builder,
|
||||
auto *FieldTy = cast<IntegerType>(Target->getType()->getPointerElementType());
|
||||
unsigned FieldSize = FieldTy->getBitWidth() / 8;
|
||||
|
||||
// Truncate value to store
|
||||
auto *Truncated = Builder.CreateTrunc(ToStore, InputStoreTy);
|
||||
|
||||
// Are we trying to store more than it fits?
|
||||
if (StoreSize > FieldSize) {
|
||||
// It's OK as long as after what we're storing there's a hole
|
||||
assert(getByCPUStateOffsetInternal(Offset + FieldSize).first == nullptr);
|
||||
Truncated = Builder.CreateTrunc(Truncated, FieldTy);
|
||||
// If we're storing more than it fits and the following memory is not
|
||||
// padding the store is not valid.
|
||||
if (getByCPUStateOffsetInternal(Offset + FieldSize).first != nullptr)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Truncate value to store
|
||||
auto *Truncated = Builder.CreateTrunc(ToStore, InputStoreTy);
|
||||
if (StoreSize > FieldSize)
|
||||
Truncated = Builder.CreateTrunc(Truncated, FieldTy);
|
||||
|
||||
// Re-extend
|
||||
ToStore = Builder.CreateZExt(Truncated, FieldTy);
|
||||
|
||||
@@ -736,9 +341,9 @@ Value *VariableManager::loadFromCPUStateOffset(IRBuilder<> &Builder,
|
||||
// Extract the desired part
|
||||
// Shift right of the desired amount
|
||||
unsigned ShiftAmount = 0;
|
||||
if (TargetArchitecture.isLittleEndian())
|
||||
if (TargetArchitecture.isLittleEndian()) {
|
||||
ShiftAmount = Remaining;
|
||||
else {
|
||||
} else {
|
||||
// >> (Size1 - Size2) - Remaining;
|
||||
auto *LoadedTy = cast<IntegerType>(LoadEnvField->getType());
|
||||
unsigned GlobalSize = LoadedTy->getBitWidth() / 8;
|
||||
@@ -757,8 +362,10 @@ Value *VariableManager::loadFromCPUStateOffset(IRBuilder<> &Builder,
|
||||
if (auto FieldTy = dyn_cast<IntegerType>(Result->getType())) {
|
||||
unsigned FieldSize = FieldTy->getBitWidth() / 8;
|
||||
if (FieldSize < LoadSize) {
|
||||
// It's OK as long as after what we can't load there's a hole
|
||||
assert(getByCPUStateOffsetInternal(Offset + FieldSize).first == nullptr);
|
||||
// If after what we are loading ther is something that is not padding we
|
||||
// cannot load safely
|
||||
if (getByCPUStateOffsetInternal(Offset + FieldSize).first != nullptr)
|
||||
return nullptr;
|
||||
Result = Builder.CreateZExt(Result, LoadTy);
|
||||
}
|
||||
}
|
||||
@@ -767,6 +374,59 @@ Value *VariableManager::loadFromCPUStateOffset(IRBuilder<> &Builder,
|
||||
return Builder.CreateTrunc(Result, LoadTy);
|
||||
}
|
||||
|
||||
|
||||
bool VariableManager::memcpyAtEnvOffset(llvm::IRBuilder<> &Builder,
|
||||
llvm::CallInst *CallMemcpy,
|
||||
unsigned InitialEnvOffset,
|
||||
bool EnvIsSrc) {
|
||||
Function *Callee = getCallee(CallMemcpy);
|
||||
// We only support memcpys where the last parameter is constant
|
||||
assert(Callee != nullptr
|
||||
and (Callee->getIntrinsicID() == Intrinsic::memcpy
|
||||
and isa<ConstantInt>(CallMemcpy->getArgOperand(2))));
|
||||
|
||||
Value *OtherOp = CallMemcpy->getArgOperand(EnvIsSrc ? 0 : 1);
|
||||
auto *MemcpySize = cast<Constant>(CallMemcpy->getArgOperand(2));
|
||||
Value *OtherBasePtr = Builder.CreatePtrToInt(OtherOp, Builder.getInt64Ty());
|
||||
|
||||
uint64_t TotalSize = getZExtValue(MemcpySize, *ModuleLayout);
|
||||
uint64_t Offset = 0;
|
||||
|
||||
bool OnlyPointersAndPadding = true;
|
||||
while (Offset < TotalSize) {
|
||||
GlobalVariable *EnvVar = getByEnvOffset(InitialEnvOffset + Offset).first;
|
||||
|
||||
// Consider the case when there's simply nothing there (alignment space).
|
||||
if (EnvVar == nullptr) {
|
||||
if (false and EnvIsSrc) { // TODO: remove "false and", but after adding type based stuff
|
||||
ConstantInt *ZeroByte = Builder.getInt8(0);
|
||||
Value *NewAddress = Builder.CreateAdd(Builder.getInt64(Offset), OtherBasePtr);
|
||||
Value *OtherPtr = Builder.CreateIntToPtr(NewAddress, Builder.getInt8Ty()->getPointerTo());
|
||||
Builder.CreateStore(ZeroByte, OtherPtr);
|
||||
OnlyPointersAndPadding = false;
|
||||
}
|
||||
Offset++;
|
||||
continue;
|
||||
}
|
||||
OnlyPointersAndPadding = false;
|
||||
|
||||
Value *NewAddress = Builder.CreateAdd(Builder.getInt64(Offset), OtherBasePtr);
|
||||
Value *OtherPtr = Builder.CreateIntToPtr(NewAddress, EnvVar->getType());
|
||||
|
||||
Value *Dst = EnvIsSrc ? OtherPtr : EnvVar;
|
||||
Value *Src = EnvIsSrc ? EnvVar : OtherPtr;
|
||||
Builder.CreateStore(Builder.CreateLoad(Src), Dst);
|
||||
|
||||
Type *PointeeTy = EnvVar->getType()->getPointerElementType();
|
||||
Offset += ModuleLayout->getTypeAllocSize(PointeeTy);
|
||||
}
|
||||
|
||||
if (OnlyPointersAndPadding)
|
||||
cast<Instruction>(OtherBasePtr)->eraseFromParent();
|
||||
|
||||
return Offset == TotalSize;
|
||||
}
|
||||
|
||||
// TODO: `newFunction` reflects the tcg terminology but in this context is
|
||||
// highly misleading
|
||||
void VariableManager::newFunction(Instruction *Delimiter,
|
||||
@@ -837,9 +497,6 @@ GlobalVariable* VariableManager::getByCPUStateOffset(intptr_t Offset,
|
||||
std::pair<GlobalVariable*, unsigned>
|
||||
VariableManager::getByCPUStateOffsetInternal(intptr_t Offset,
|
||||
std::string Name) {
|
||||
if (Offset == ErrorOffset)
|
||||
return { nullptr, 0 };
|
||||
|
||||
GlobalsMap::iterator it = CPUStateGlobals.find(Offset);
|
||||
if (it == CPUStateGlobals.end() ||
|
||||
(Name.size() != 0 && !it->second->getName().equals_lower(Name))) {
|
||||
@@ -849,6 +506,10 @@ VariableManager::getByCPUStateOffsetInternal(intptr_t Offset,
|
||||
CPUStateType,
|
||||
Offset);
|
||||
|
||||
// Unsupported type, let the caller handle the situation
|
||||
if (VariableType == nullptr)
|
||||
return { nullptr, 0 };
|
||||
|
||||
// Check we're not trying to go inside an existing variable
|
||||
if (Remaining != 0) {
|
||||
GlobalsMap::iterator it = CPUStateGlobals.find(Offset - Remaining);
|
||||
@@ -856,10 +517,6 @@ VariableManager::getByCPUStateOffsetInternal(intptr_t Offset,
|
||||
return { it->second, Remaining };
|
||||
}
|
||||
|
||||
// Unsupported type, let the caller handle the situation
|
||||
if (VariableType == nullptr)
|
||||
return { nullptr, 0 };
|
||||
|
||||
if (Name.size() == 0) {
|
||||
std::stringstream NameStream;
|
||||
NameStream << "state_0x" << std::hex << Offset;
|
||||
|
||||
Reference in New Issue
Block a user