[lldb] Handle ConstantExpr constants in InjectPointerSigningFixupCode (#194476)
Currently, the injection code assumes we encounter ConstantAggregate constants and emits a GEP to access the fields/members. However, it's possible for a CPA to be an operand of a ConstantExpr (e.g. a bitcast). Emitting a GEP in that scenario doesn't make sense. This should instead be handled by keeping track of the path to the CPA (which operands need to be followed from the top-level ConstantExpr). After this change, most arm64e tests that crash LLDB either pass or fail with some other issue. The main exception is TestWeakSymbols.py which needs more work.
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
@@ -45,31 +46,54 @@
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
struct ExprStep {
|
||||
ConstantExpr *CE;
|
||||
unsigned OperandIdx;
|
||||
};
|
||||
|
||||
struct PtrAuthFixup {
|
||||
GlobalVariable *GV;
|
||||
ConstantPtrAuth *CPA;
|
||||
SmallVector<unsigned> Indices;
|
||||
/// ConstantAggregate types are walekd via GEP indices.
|
||||
SmallVector<unsigned> GEPPath;
|
||||
/// ConstantExpr types are traversed via ExprStep (ConstantExpr + Operand
|
||||
/// index).
|
||||
SmallVector<ExprStep> ExprPath;
|
||||
PtrAuthFixup(GlobalVariable *GV, ConstantPtrAuth *CPA,
|
||||
const SmallVectorImpl<unsigned> &Indices)
|
||||
: GV(GV), CPA(CPA), Indices(Indices.begin(), Indices.end()) {}
|
||||
const SmallVectorImpl<unsigned> &GEPPath,
|
||||
const SmallVectorImpl<ExprStep> &ExprPath)
|
||||
: GV(GV), CPA(CPA), GEPPath(GEPPath.begin(), GEPPath.end()),
|
||||
ExprPath(ExprPath.begin(), ExprPath.end()) {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
/// Recursively walk a constant looking for ConstantPtrAuth expressions.
|
||||
/// When found, record the global variable containing the ConstantPtrAuth and
|
||||
/// the index path to reach it within the initializer.
|
||||
static void findPtrAuth(Constant *C, GlobalVariable &GV,
|
||||
SmallVectorImpl<unsigned> &Indices,
|
||||
SmallVectorImpl<unsigned> &GEPPath,
|
||||
SmallVectorImpl<ExprStep> &ExprPath,
|
||||
SmallVectorImpl<PtrAuthFixup> &Fixups) {
|
||||
if (auto *CPA = dyn_cast<ConstantPtrAuth>(C)) {
|
||||
Fixups.emplace_back(&GV, CPA, Indices);
|
||||
Fixups.emplace_back(&GV, CPA, GEPPath, ExprPath);
|
||||
return;
|
||||
}
|
||||
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
|
||||
if (auto *COp = dyn_cast<Constant>(C->getOperand(I))) {
|
||||
Indices.push_back(I);
|
||||
findPtrAuth(COp, GV, Indices, Fixups);
|
||||
Indices.pop_back();
|
||||
if (isa<ConstantAggregate>(C)) {
|
||||
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
|
||||
if (auto *COp = dyn_cast<Constant>(C->getOperand(I))) {
|
||||
GEPPath.push_back(I);
|
||||
findPtrAuth(COp, GV, GEPPath, ExprPath, Fixups);
|
||||
GEPPath.pop_back();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto *CE = dyn_cast<ConstantExpr>(C)) {
|
||||
for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) {
|
||||
if (auto *COp = dyn_cast<Constant>(C->getOperand(I))) {
|
||||
ExprPath.push_back({CE, I});
|
||||
findPtrAuth(COp, GV, GEPPath, ExprPath, Fixups);
|
||||
ExprPath.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,8 +117,9 @@ Error InjectPointerSigningFixupCode(llvm::Module &M,
|
||||
for (auto &G : M.globals()) {
|
||||
if (!G.hasInitializer())
|
||||
continue;
|
||||
SmallVector<unsigned> Indices;
|
||||
findPtrAuth(G.getInitializer(), G, Indices, Fixups);
|
||||
SmallVector<unsigned> GEPPath;
|
||||
SmallVector<ExprStep> ExprPath;
|
||||
findPtrAuth(G.getInitializer(), G, GEPPath, ExprPath, Fixups);
|
||||
}
|
||||
|
||||
if (Fixups.empty())
|
||||
@@ -126,37 +151,50 @@ Error InjectPointerSigningFixupCode(llvm::Module &M,
|
||||
continue;
|
||||
}
|
||||
|
||||
// Build a GEP to the location of the ConstantPtrAuth within the global.
|
||||
// Build a GEP to the location of the ConstantPtrAuth (or the expression
|
||||
// path to the ConstantPtrAuth) within the global.
|
||||
Value *Loc;
|
||||
if (Fixup.Indices.empty()) {
|
||||
if (Fixup.GEPPath.empty()) {
|
||||
Loc = GV;
|
||||
} else {
|
||||
SmallVector<Value *> GEPIndices;
|
||||
GEPIndices.push_back(ConstantInt::get(Int32Ty, 0));
|
||||
for (unsigned Idx : Fixup.Indices)
|
||||
GEPIndices.push_back(ConstantInt::get(Int32Ty, Idx));
|
||||
Loc = B.CreateGEP(GV->getValueType(), GV, GEPIndices);
|
||||
SmallVector<Value *> GEPValues;
|
||||
GEPValues.push_back(ConstantInt::get(Int32Ty, 0));
|
||||
for (unsigned Idx : Fixup.GEPPath)
|
||||
GEPValues.push_back(ConstantInt::get(Int32Ty, Idx));
|
||||
Loc = B.CreateGEP(GV->getValueType(), GV, GEPValues);
|
||||
}
|
||||
|
||||
Type *PtrTy = CPA->getType();
|
||||
|
||||
// Load the raw (unsigned) pointer.
|
||||
Value *RawPtr = B.CreateLoad(PtrTy, Loc);
|
||||
|
||||
// Compute the discriminator, blending with the address if needed.
|
||||
Value *Disc = CPA->getDiscriminator();
|
||||
if (CPA->hasAddressDiscriminator())
|
||||
Disc = B.CreateCall(BlendIntrinsic,
|
||||
{B.CreatePointerCast(Loc, IntPtrTy), Disc});
|
||||
|
||||
// Sign the pointer.
|
||||
Value *SignedPtr =
|
||||
B.CreateCall(SignIntrinsic, {B.CreatePointerCast(RawPtr, IntPtrTy),
|
||||
CPA->getKey(), Disc});
|
||||
|
||||
// Store the signed pointer back.
|
||||
B.CreateStore(B.CreateBitOrPointerCast(SignedPtr, PtrTy), Loc);
|
||||
if (!Fixup.ExprPath.empty()) {
|
||||
// The CPA is wrapped in a ConstantExpr chain. Sign the CPA's pointer
|
||||
// directly and re-evaluate the expr chain.
|
||||
Value *SignedPtr = B.CreateCall(
|
||||
SignIntrinsic, {B.CreatePointerCast(CPA->getPointer(), IntPtrTy),
|
||||
CPA->getKey(), Disc});
|
||||
Value *Result = B.CreateIntToPtr(SignedPtr, PtrTy);
|
||||
|
||||
for (auto &Step : llvm::reverse(Fixup.ExprPath)) {
|
||||
Instruction *I = Step.CE->getAsInstruction();
|
||||
I->setOperand(Step.OperandIdx, Result);
|
||||
B.Insert(I);
|
||||
Result = I;
|
||||
}
|
||||
B.CreateStore(Result, Loc);
|
||||
} else {
|
||||
// There is no expression chain. Load and sign the pointer directly.
|
||||
Value *RawPtr = B.CreateLoad(PtrTy, Loc);
|
||||
Value *SignedPtr =
|
||||
B.CreateCall(SignIntrinsic, {B.CreatePointerCast(RawPtr, IntPtrTy),
|
||||
CPA->getKey(), Disc});
|
||||
B.CreateStore(B.CreateBitOrPointerCast(SignedPtr, PtrTy), Loc);
|
||||
}
|
||||
// Replace the ConstantPtrAuth in the initializer with the unsigned pointer.
|
||||
CPA->replaceAllUsesWith(CPA->getPointer());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user