|
33 | 33 | #include "llvm/Support/CommandLine.h" |
34 | 34 | #include "llvm/Support/SpecialCaseList.h" |
35 | 35 | #include "llvm/Support/VirtualFileSystem.h" |
| 36 | +#include "llvm/Support/raw_ostream.h" |
36 | 37 | #include "llvm/TargetParser/Triple.h" |
37 | 38 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" |
38 | 39 | #include "llvm/Transforms/Utils/ModuleUtils.h" |
@@ -86,6 +87,7 @@ const char SanCovPCsSectionName[] = "sancov_pcs"; |
86 | 87 | const char SanCovCFsSectionName[] = "sancov_cfs"; |
87 | 88 | const char SanCovCallbackGateSectionName[] = "sancov_gate"; |
88 | 89 |
|
| 90 | +const char SanCovStackDepthCallbackName[] = "__sanitizer_cov_stack_depth"; |
89 | 91 | const char SanCovLowestStackName[] = "__sancov_lowest_stack"; |
90 | 92 | const char SanCovCallbackGateName[] = "__sancov_should_track"; |
91 | 93 |
|
@@ -152,6 +154,12 @@ static cl::opt<bool> ClStackDepth("sanitizer-coverage-stack-depth", |
152 | 154 | cl::desc("max stack depth tracing"), |
153 | 155 | cl::Hidden); |
154 | 156 |
|
| 157 | +static cl::opt<int> ClStackDepthCallbackMin( |
| 158 | + "sanitizer-coverage-stack-depth-callback-min", |
| 159 | + cl::desc("max stack depth tracing should use callback and only when " |
| 160 | + "stack depth more than specified"), |
| 161 | + cl::Hidden); |
| 162 | + |
155 | 163 | static cl::opt<bool> |
156 | 164 | ClCollectCF("sanitizer-coverage-control-flow", |
157 | 165 | cl::desc("collect control flow for each function"), cl::Hidden); |
@@ -202,6 +210,8 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) { |
202 | 210 | Options.PCTable |= ClCreatePCTable; |
203 | 211 | Options.NoPrune |= !ClPruneBlocks; |
204 | 212 | Options.StackDepth |= ClStackDepth; |
| 213 | + Options.StackDepthCallbackMin = std::max(Options.StackDepthCallbackMin, |
| 214 | + ClStackDepthCallbackMin.getValue()); |
205 | 215 | Options.TraceLoads |= ClLoadTracing; |
206 | 216 | Options.TraceStores |= ClStoreTracing; |
207 | 217 | Options.GatedCallbacks |= ClGatedCallbacks; |
@@ -271,6 +281,7 @@ class ModuleSanitizerCoverage { |
271 | 281 | DomTreeCallback DTCallback; |
272 | 282 | PostDomTreeCallback PDTCallback; |
273 | 283 |
|
| 284 | + FunctionCallee SanCovStackDepthCallback; |
274 | 285 | FunctionCallee SanCovTracePCIndir; |
275 | 286 | FunctionCallee SanCovTracePC, SanCovTracePCGuard; |
276 | 287 | std::array<FunctionCallee, 4> SanCovTraceCmpFunction; |
@@ -514,6 +525,9 @@ bool ModuleSanitizerCoverage::instrumentModule() { |
514 | 525 | SanCovTracePCGuard = |
515 | 526 | M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, PtrTy); |
516 | 527 |
|
| 528 | + SanCovStackDepthCallback = |
| 529 | + M.getOrInsertFunction(SanCovStackDepthCallbackName, VoidTy); |
| 530 | + |
517 | 531 | for (auto &F : M) |
518 | 532 | instrumentFunction(F); |
519 | 533 |
|
@@ -1029,6 +1043,8 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, |
1029 | 1043 | if (IsEntryBB) { |
1030 | 1044 | if (auto SP = F.getSubprogram()) |
1031 | 1045 | EntryLoc = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); |
| 1046 | + // FIXME: stack-depth does not correctly instrument dynamic allocas. |
| 1047 | + // |
1032 | 1048 | // Keep static allocas and llvm.localescape calls in the entry block. Even |
1033 | 1049 | // if we aren't splitting the block, it's nice for allocas to be before |
1034 | 1050 | // calls. |
@@ -1078,22 +1094,50 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, |
1078 | 1094 | Store->setNoSanitizeMetadata(); |
1079 | 1095 | } |
1080 | 1096 | if (Options.StackDepth && IsEntryBB && !IsLeafFunc) { |
1081 | | - // Check stack depth. If it's the deepest so far, record it. |
1082 | 1097 | Module *M = F.getParent(); |
1083 | | - auto FrameAddrPtr = IRB.CreateIntrinsic( |
1084 | | - Intrinsic::frameaddress, |
1085 | | - IRB.getPtrTy(M->getDataLayout().getAllocaAddrSpace()), |
1086 | | - {Constant::getNullValue(Int32Ty)}); |
1087 | | - auto FrameAddrInt = IRB.CreatePtrToInt(FrameAddrPtr, IntptrTy); |
1088 | | - auto LowestStack = IRB.CreateLoad(IntptrTy, SanCovLowestStack); |
1089 | | - auto IsStackLower = IRB.CreateICmpULT(FrameAddrInt, LowestStack); |
1090 | | - auto ThenTerm = SplitBlockAndInsertIfThen( |
1091 | | - IsStackLower, &*IP, false, |
1092 | | - MDBuilder(IRB.getContext()).createUnlikelyBranchWeights()); |
1093 | | - IRBuilder<> ThenIRB(ThenTerm); |
1094 | | - auto Store = ThenIRB.CreateStore(FrameAddrInt, SanCovLowestStack); |
1095 | | - LowestStack->setNoSanitizeMetadata(); |
1096 | | - Store->setNoSanitizeMetadata(); |
| 1098 | + if (Options.StackDepthCallbackMin) { |
| 1099 | + // In callback mode, only add call when stack depth reaches minimum. |
| 1100 | + const DataLayout &DL = M->getDataLayout(); |
| 1101 | + uint32_t EstimatedStackSize = 0; |
| 1102 | + |
| 1103 | + // Make an estimate on the stack usage. |
| 1104 | + for (auto &I : F.getEntryBlock()) { |
| 1105 | + if (auto *AI = dyn_cast<AllocaInst>(&I)) { |
| 1106 | + if (AI->isStaticAlloca()) { |
| 1107 | + uint32_t Bytes = DL.getTypeAllocSize(AI->getAllocatedType()); |
| 1108 | + if (AI->isArrayAllocation()) { |
| 1109 | + if (const ConstantInt *arraySize = |
| 1110 | + dyn_cast<ConstantInt>(AI->getArraySize())) |
| 1111 | + Bytes *= arraySize->getZExtValue(); |
| 1112 | + } |
| 1113 | + EstimatedStackSize += Bytes; |
| 1114 | + } else { |
| 1115 | + // Dynamic alloca: require we always perform callback. |
| 1116 | + EstimatedStackSize = Options.StackDepthCallbackMin; |
| 1117 | + break; |
| 1118 | + } |
| 1119 | + } |
| 1120 | + } |
| 1121 | + |
| 1122 | + if (EstimatedStackSize >= Options.StackDepthCallbackMin) |
| 1123 | + IRB.CreateCall(SanCovStackDepthCallback)->setCannotMerge(); |
| 1124 | + } else { |
| 1125 | + // Check stack depth. If it's the deepest so far, record it. |
| 1126 | + auto FrameAddrPtr = IRB.CreateIntrinsic( |
| 1127 | + Intrinsic::frameaddress, |
| 1128 | + IRB.getPtrTy(M->getDataLayout().getAllocaAddrSpace()), |
| 1129 | + {Constant::getNullValue(Int32Ty)}); |
| 1130 | + auto FrameAddrInt = IRB.CreatePtrToInt(FrameAddrPtr, IntptrTy); |
| 1131 | + auto LowestStack = IRB.CreateLoad(IntptrTy, SanCovLowestStack); |
| 1132 | + auto IsStackLower = IRB.CreateICmpULT(FrameAddrInt, LowestStack); |
| 1133 | + auto ThenTerm = SplitBlockAndInsertIfThen( |
| 1134 | + IsStackLower, &*IP, false, |
| 1135 | + MDBuilder(IRB.getContext()).createUnlikelyBranchWeights()); |
| 1136 | + IRBuilder<> ThenIRB(ThenTerm); |
| 1137 | + auto Store = ThenIRB.CreateStore(FrameAddrInt, SanCovLowestStack); |
| 1138 | + LowestStack->setNoSanitizeMetadata(); |
| 1139 | + Store->setNoSanitizeMetadata(); |
| 1140 | + } |
1097 | 1141 | } |
1098 | 1142 | } |
1099 | 1143 |
|
|
0 commit comments