mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-29 10:25:12 +00:00
[asan] more code to merge crash callbacks. Doesn't fully work yet, but allows to hold performance experiments
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@160361 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -144,6 +144,14 @@ static cl::opt<int> ClDebugMax("asan-debug-max", cl::desc("Debug man inst"),
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
/// When the crash callbacks are merged, they receive some amount of arguments
|
||||||
|
/// that are merged in a PHI node. This struct represents arguments from one
|
||||||
|
/// call site.
|
||||||
|
struct CrashArg {
|
||||||
|
Value *Arg1;
|
||||||
|
Value *Arg2;
|
||||||
|
};
|
||||||
|
|
||||||
/// An object of this type is created while instrumenting every function.
|
/// An object of this type is created while instrumenting every function.
|
||||||
struct AsanFunctionContext {
|
struct AsanFunctionContext {
|
||||||
AsanFunctionContext(Function &Function) : F(Function), CrashBlock() { }
|
AsanFunctionContext(Function &Function) : F(Function), CrashBlock() { }
|
||||||
@@ -152,6 +160,8 @@ struct AsanFunctionContext {
|
|||||||
// These are initially zero. If we require at least one call to
|
// These are initially zero. If we require at least one call to
|
||||||
// __asan_report_{read,write}{1,2,4,8,16}, an appropriate BB is created.
|
// __asan_report_{read,write}{1,2,4,8,16}, an appropriate BB is created.
|
||||||
BasicBlock *CrashBlock[2][kNumberOfAccessSizes];
|
BasicBlock *CrashBlock[2][kNumberOfAccessSizes];
|
||||||
|
typedef SmallVector<CrashArg, 8> CrashArgsVec;
|
||||||
|
CrashArgsVec CrashArgs[2][kNumberOfAccessSizes];
|
||||||
};
|
};
|
||||||
|
|
||||||
/// AddressSanitizer: instrument the code in module to find memory bugs.
|
/// AddressSanitizer: instrument the code in module to find memory bugs.
|
||||||
@@ -164,7 +174,7 @@ struct AddressSanitizer : public ModulePass {
|
|||||||
Value *Addr, uint32_t TypeSize, bool IsWrite);
|
Value *Addr, uint32_t TypeSize, bool IsWrite);
|
||||||
Value *createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
|
Value *createSlowPathCmp(IRBuilder<> &IRB, Value *AddrLong,
|
||||||
Value *ShadowValue, uint32_t TypeSize);
|
Value *ShadowValue, uint32_t TypeSize);
|
||||||
Instruction *generateCrashCode(BasicBlock *BB, Value *Addr,
|
Instruction *generateCrashCode(BasicBlock *BB, Value *Addr, Value *PC,
|
||||||
bool IsWrite, size_t AccessSizeIndex);
|
bool IsWrite, size_t AccessSizeIndex);
|
||||||
bool instrumentMemIntrinsic(AsanFunctionContext &AFC, MemIntrinsic *MI);
|
bool instrumentMemIntrinsic(AsanFunctionContext &AFC, MemIntrinsic *MI);
|
||||||
void instrumentMemIntrinsicParam(AsanFunctionContext &AFC,
|
void instrumentMemIntrinsicParam(AsanFunctionContext &AFC,
|
||||||
@@ -395,10 +405,15 @@ Function *AddressSanitizer::checkInterfaceFunction(Constant *FuncOrBitcast) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Instruction *AddressSanitizer::generateCrashCode(
|
Instruction *AddressSanitizer::generateCrashCode(
|
||||||
BasicBlock *BB, Value *Addr, bool IsWrite, size_t AccessSizeIndex) {
|
BasicBlock *BB, Value *Addr, Value *PC,
|
||||||
|
bool IsWrite, size_t AccessSizeIndex) {
|
||||||
IRBuilder<> IRB(BB->getFirstNonPHI());
|
IRBuilder<> IRB(BB->getFirstNonPHI());
|
||||||
CallInst *Call = IRB.CreateCall(AsanErrorCallback[IsWrite][AccessSizeIndex],
|
CallInst *Call;
|
||||||
Addr);
|
if (PC)
|
||||||
|
Call = IRB.CreateCall2(AsanErrorCallback[IsWrite][AccessSizeIndex],
|
||||||
|
Addr, PC);
|
||||||
|
else
|
||||||
|
Call = IRB.CreateCall(AsanErrorCallback[IsWrite][AccessSizeIndex], Addr);
|
||||||
Call->setDoesNotReturn();
|
Call->setDoesNotReturn();
|
||||||
return Call;
|
return Call;
|
||||||
}
|
}
|
||||||
@@ -439,20 +454,30 @@ void AddressSanitizer::instrumentAddress(AsanFunctionContext &AFC,
|
|||||||
|
|
||||||
BasicBlock *CrashBlock = 0;
|
BasicBlock *CrashBlock = 0;
|
||||||
if (ClMergeCallbacks) {
|
if (ClMergeCallbacks) {
|
||||||
BasicBlock **Cached =
|
size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
|
||||||
&AFC.CrashBlock[IsWrite][TypeSizeToSizeIndex(TypeSize)];
|
BasicBlock **Cached = &AFC.CrashBlock[IsWrite][AccessSizeIndex];
|
||||||
if (!*Cached) {
|
if (!*Cached) {
|
||||||
BasicBlock *BB = BasicBlock::Create(*C, "crash_bb", &AFC.F);
|
std::string BBName("crash_bb-");
|
||||||
|
BBName += (IsWrite ? "w-" : "r-") + itostr(1 << AccessSizeIndex);
|
||||||
|
BasicBlock *BB = BasicBlock::Create(*C, BBName, &AFC.F);
|
||||||
new UnreachableInst(*C, BB);
|
new UnreachableInst(*C, BB);
|
||||||
*Cached = BB;
|
*Cached = BB;
|
||||||
}
|
}
|
||||||
CrashBlock = *Cached;
|
CrashBlock = *Cached;
|
||||||
|
// We need to pass the PC as the second parameter to __asan_report_*.
|
||||||
|
// There are few problems:
|
||||||
|
// - Some architectures (e.g. x86_32) don't have a cheap way to get the PC.
|
||||||
|
// - LLVM doesn't have the appropriate intrinsic.
|
||||||
|
// For now, put a random number into the PC, just to allow experiments.
|
||||||
|
Value *PC = ConstantInt::get(IntptrTy, rand());
|
||||||
|
CrashArg Arg = {AddrLong, PC};
|
||||||
|
AFC.CrashArgs[IsWrite][AccessSizeIndex].push_back(Arg);
|
||||||
} else {
|
} else {
|
||||||
CrashBlock = BasicBlock::Create(*C, "crash_bb", &AFC.F);
|
CrashBlock = BasicBlock::Create(*C, "crash_bb", &AFC.F);
|
||||||
new UnreachableInst(*C, CrashBlock);
|
new UnreachableInst(*C, CrashBlock);
|
||||||
size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
|
size_t AccessSizeIndex = TypeSizeToSizeIndex(TypeSize);
|
||||||
Instruction *Crash =
|
Instruction *Crash =
|
||||||
generateCrashCode(CrashBlock, AddrLong, IsWrite, AccessSizeIndex);
|
generateCrashCode(CrashBlock, AddrLong, 0, IsWrite, AccessSizeIndex);
|
||||||
Crash->setDebugLoc(OrigIns->getDebugLoc());
|
Crash->setDebugLoc(OrigIns->getDebugLoc());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,8 +685,14 @@ bool AddressSanitizer::runOnModule(Module &M) {
|
|||||||
// IsWrite and TypeSize are encoded in the function name.
|
// IsWrite and TypeSize are encoded in the function name.
|
||||||
std::string FunctionName = std::string(kAsanReportErrorTemplate) +
|
std::string FunctionName = std::string(kAsanReportErrorTemplate) +
|
||||||
(AccessIsWrite ? "store" : "load") + itostr(1 << AccessSizeIndex);
|
(AccessIsWrite ? "store" : "load") + itostr(1 << AccessSizeIndex);
|
||||||
AsanErrorCallback[AccessIsWrite][AccessSizeIndex] = cast<Function>(
|
// If we are merging crash callbacks, they have two parameters.
|
||||||
M.getOrInsertFunction(FunctionName, IRB.getVoidTy(), IntptrTy, NULL));
|
if (ClMergeCallbacks)
|
||||||
|
AsanErrorCallback[AccessIsWrite][AccessSizeIndex] = cast<Function>(
|
||||||
|
M.getOrInsertFunction(FunctionName, IRB.getVoidTy(), IntptrTy,
|
||||||
|
IntptrTy, NULL));
|
||||||
|
else
|
||||||
|
AsanErrorCallback[AccessIsWrite][AccessSizeIndex] = cast<Function>(
|
||||||
|
M.getOrInsertFunction(FunctionName, IRB.getVoidTy(), IntptrTy, NULL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,14 +833,29 @@ bool AddressSanitizer::handleFunction(Module &M, Function &F) {
|
|||||||
NumInstrumented++;
|
NumInstrumented++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create PHI nodes and crash callbacks if we are merging crash callbacks.
|
||||||
if (NumInstrumented) {
|
if (NumInstrumented) {
|
||||||
for (size_t IsWrite = 0; IsWrite <= 1; IsWrite++) {
|
for (size_t IsWrite = 0; IsWrite <= 1; IsWrite++) {
|
||||||
for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
|
for (size_t AccessSizeIndex = 0; AccessSizeIndex < kNumberOfAccessSizes;
|
||||||
AccessSizeIndex++) {
|
AccessSizeIndex++) {
|
||||||
BasicBlock *BB = AFC.CrashBlock[IsWrite][AccessSizeIndex];
|
BasicBlock *BB = AFC.CrashBlock[IsWrite][AccessSizeIndex];
|
||||||
if (!BB) continue;
|
if (!BB) continue;
|
||||||
generateCrashCode(BB, ConstantInt::get(IntptrTy, 0),
|
assert(ClMergeCallbacks);
|
||||||
IsWrite, AccessSizeIndex);
|
AsanFunctionContext::CrashArgsVec &Args =
|
||||||
|
AFC.CrashArgs[IsWrite][AccessSizeIndex];
|
||||||
|
IRBuilder<> IRB(BB->getFirstNonPHI());
|
||||||
|
size_t n = Args.size();
|
||||||
|
PHINode *PN1 = IRB.CreatePHI(IntptrTy, n);
|
||||||
|
PHINode *PN2 = IRB.CreatePHI(IntptrTy, n);
|
||||||
|
// We need to match crash parameters and the predecessors.
|
||||||
|
for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
|
||||||
|
PI != PE; ++PI) {
|
||||||
|
n--;
|
||||||
|
PN1->addIncoming(Args[n].Arg1, *PI);
|
||||||
|
PN2->addIncoming(Args[n].Arg2, *PI);
|
||||||
|
}
|
||||||
|
assert(n == 0);
|
||||||
|
generateCrashCode(BB, PN1, PN2, IsWrite, AccessSizeIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user