Skip to content
ShadowStackCollector.cpp 16.5 KiB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
//===-- ShadowStackCollector.cpp - GC support for uncooperative targets ---===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements lowering for the llvm.gc* intrinsics for targets that do
// not natively support them (which includes the C backend). Note that the code
// generated is not quite as efficient as collectors which generate stack maps
// to identify roots.
//
// This pass implements the code transformation described in this paper:
//   "Accurate Garbage Collection in an Uncooperative Environment"
//   Fergus Henderson, ISMM, 2002
//
// In runtime/GC/SemiSpace.cpp is a prototype runtime which is compatible with
// this collector.
//
// In order to support this particular transformation, all stack roots are
// coallocated in the stack. This allows a fully target-independent stack map
// while introducing only minor runtime overhead.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "shadowstackgc"
#include "llvm/CodeGen/Collectors.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CodeGen/Collector.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Module.h"
#include "llvm/Support/LLVMBuilder.h"

using namespace llvm;

namespace {
  
  class VISIBILITY_HIDDEN ShadowStackCollector : public Collector {
    /// RootChain - This is the global linked-list that contains the chain of GC
    /// roots.
    GlobalVariable *Head;
    
    /// StackEntryTy - Abstract type of a link in the shadow stack.
    /// 
    const StructType *StackEntryTy;
    
    /// Roots - GC roots in the current function. Each is a pair of the
    /// intrinsic call and its corresponding alloca.
    std::vector<std::pair<CallInst*,AllocaInst*> > Roots;
    
  public:
    ShadowStackCollector();
    
    bool initializeCustomLowering(Module &M);
    bool performCustomLowering(Function &F);
    
  private:
    bool IsNullValue(Value *V);
    Constant *GetFrameMap(Function &F);
    const Type* GetConcreteStackEntryType(Function &F);
    void CollectRoots(Function &F);
    static GetElementPtrInst *CreateGEP(LLVMBuilder &B, Value *BasePtr,
                                        int Idx1, const char *Name);
    static GetElementPtrInst *CreateGEP(LLVMBuilder &B, Value *BasePtr,
                                        int Idx1, int Idx2, const char *Name);
  };
  
  CollectorRegistry::Add<ShadowStackCollector>
  Y("shadow-stack",
    "Very portable collector for uncooperative code generators");
  
  /// EscapeEnumerator - This is a little algorithm to find all escape points
  /// from a function so that "finally"-style code can be inserted. In addition
  /// to finding the existing return and unwind instructions, it also (if
  /// necessary) transforms any call instructions into invokes and sends them to
  /// a landing pad.
  /// 
  /// It's wrapped up in a state machine using the same transform C# uses for
  /// 'yield return' enumerators, This transform allows it to be non-allocating.
  class VISIBILITY_HIDDEN EscapeEnumerator {
    Function &F;
    const char *CleanupBBName;
    
    // State.
    int State;
    Function::iterator StateBB, StateE;
    LLVMBuilder Builder;
    
  public:
    EscapeEnumerator(Function &F, const char *N = "cleanup")
      : F(F), CleanupBBName(N), State(0) {}
    
    LLVMBuilder *Next() {
      switch (State) {
      default:
        return 0;
        
      case 0:
        StateBB = F.begin();
        StateE = F.end();
        State = 1;
        
      case 1:
        // Find all 'return' and 'unwind' instructions.
        while (StateBB != StateE) {
          BasicBlock *CurBB = StateBB++;
          
          // Branches and invokes do not escape, only unwind and return do.
          TerminatorInst *TI = CurBB->getTerminator();
          if (!isa<UnwindInst>(TI) && !isa<ReturnInst>(TI))
            continue;
          
          Builder.SetInsertPoint(TI->getParent(), TI);
          return &Builder;
        }
        
        State = 2;
        
        // Find all 'call' instructions.
        SmallVector<Instruction*,16> Calls;
        for (Function::iterator BB = F.begin(),
                                E = F.end(); BB != E; ++BB)
          for (BasicBlock::iterator II = BB->begin(),
                                    EE = BB->end(); II != EE; ++II)
            if (CallInst *CI = dyn_cast<CallInst>(II))
              if (!CI->getCalledFunction() ||
                  !CI->getCalledFunction()->getIntrinsicID())
                Calls.push_back(CI);
        
        if (Calls.empty())
          return 0;
        
        // Create a cleanup block.
        BasicBlock *CleanupBB = new BasicBlock(CleanupBBName, &F);
        UnwindInst *UI = new UnwindInst(CleanupBB);
        
        // Transform the 'call' instructions into 'invoke's branching to the
        // cleanup block. Go in reverse order to make prettier BB names.
        SmallVector<Value*,16> Args;
        for (unsigned I = Calls.size(); I != 0; ) {
          CallInst *CI = cast<CallInst>(Calls[--I]);
          
          // Split the basic block containing the function call.
          BasicBlock *CallBB = CI->getParent();
          BasicBlock *NewBB =
            CallBB->splitBasicBlock(CI, CallBB->getName() + ".cont");
          
          // Remove the unconditional branch inserted at the end of CallBB.
          CallBB->getInstList().pop_back();
          NewBB->getInstList().remove(CI);
          
          // Create a new invoke instruction.
          Args.clear();
          Args.append(CI->op_begin() + 1, CI->op_end());
          
          InvokeInst *II = new InvokeInst(CI->getOperand(0),
                                          NewBB, CleanupBB,
                                          Args.begin(), Args.end(),
                                          CI->getName(), CallBB);
          II->setCallingConv(CI->getCallingConv());
          II->setParamAttrs(CI->getParamAttrs());
          CI->replaceAllUsesWith(II);
          delete CI;
        }
        
        Builder.SetInsertPoint(UI->getParent(), UI);
        return &Builder;
      }
    }
  };

}

// -----------------------------------------------------------------------------

Collector *llvm::createShadowStackCollector() {
  return new ShadowStackCollector();
}

ShadowStackCollector::ShadowStackCollector() : Head(0), StackEntryTy(0) {
  InitRoots = true;
  CustomRoots = true;
}

Constant *ShadowStackCollector::GetFrameMap(Function &F) {
  // doInitialization creates the abstract type of this value.
  
  Type *VoidPtr = PointerType::getUnqual(Type::Int8Ty);
  
  // Truncate the ShadowStackDescriptor if some metadata is null.
  unsigned NumMeta = 0;
  SmallVector<Constant*,16> Metadata;
  for (unsigned I = 0; I != Roots.size(); ++I) {
    Constant *C = cast<Constant>(Roots[I].first->getOperand(2));
    if (!C->isNullValue())
      NumMeta = I + 1;
    Metadata.push_back(ConstantExpr::getBitCast(C, VoidPtr));
  }
  
  Constant *BaseElts[] = {
    ConstantInt::get(Type::Int32Ty, Roots.size(), false),
    ConstantInt::get(Type::Int32Ty, NumMeta, false),
  };
  
  Constant *DescriptorElts[] = {
    ConstantStruct::get(BaseElts, 2),
    ConstantArray::get(ArrayType::get(VoidPtr, NumMeta),
                       Metadata.begin(), NumMeta)
  };
  
  Constant *FrameMap = ConstantStruct::get(DescriptorElts, 2);
  
  std::string TypeName("gc_map.");
  TypeName += utostr(NumMeta);
  F.getParent()->addTypeName(TypeName, FrameMap->getType());
  
  // FIXME: Is this actually dangerous as WritingAnLLVMPass.html claims? Seems
  //        that, short of multithreaded LLVM, it should be safe; all that is
  //        necessary is that a simple Module::iterator loop not be invalidated.
  //        Appending to the GlobalVariable list is safe in that sense.
  // 
  //        All of the output passes emit globals last. The ExecutionEngine
  //        explicitly supports adding globals to the module after
  //        initialization.
  // 
  //        Still, if it isn't deemed acceptable, then this transformation needs
  //        to be a ModulePass (which means it cannot be in the 'llc' pipeline
  //        (which uses a FunctionPassManager (which segfaults (not asserts) if
  //        provided a ModulePass))).
  Constant *GV = new GlobalVariable(FrameMap->getType(), true,
                                    GlobalVariable::InternalLinkage,
                                    FrameMap, "__gc_" + F.getName(),
                                    F.getParent());
  
  Constant *GEPIndices[2] = { ConstantInt::get(Type::Int32Ty, 0),
                              ConstantInt::get(Type::Int32Ty, 0) };
  return ConstantExpr::getGetElementPtr(GV, GEPIndices, 2);
}

const Type* ShadowStackCollector::GetConcreteStackEntryType(Function &F) {
  // doInitialization creates the generic version of this type.
  std::vector<const Type*> EltTys;
  EltTys.push_back(StackEntryTy);
  for (size_t I = 0; I != Roots.size(); I++)
    EltTys.push_back(Roots[I].second->getAllocatedType());
  Type *Ty = StructType::get(EltTys);
  
  std::string TypeName("gc_stackentry.");
  TypeName += F.getName();
  F.getParent()->addTypeName(TypeName, Ty);
  
  return Ty;
}

/// doInitialization - If this module uses the GC intrinsics, find them now. If
/// not, exit fast.
bool ShadowStackCollector::initializeCustomLowering(Module &M) {
  // struct FrameMap {
  //   int32_t NumRoots; // Number of roots in stack frame.
  //   int32_t NumMeta;  // Number of metadata descriptors. May be < NumRoots.
  //   void *Meta[];     // May be absent for roots without metadata.
  // };
  std::vector<const Type*> EltTys;
  EltTys.push_back(Type::Int32Ty); // 32 bits is ok up to a 32GB stack frame. :)
  EltTys.push_back(Type::Int32Ty); // Specifies length of variable length array.
  StructType *FrameMapTy = StructType::get(EltTys);
  M.addTypeName("gc_map", FrameMapTy);
  PointerType *FrameMapPtrTy = PointerType::getUnqual(FrameMapTy);
  
  // struct StackEntry {
  //   ShadowStackEntry *Next; // Caller's stack entry.
  //   FrameMap *Map;          // Pointer to constant FrameMap.
  //   void *Roots[];          // Stack roots (in-place array, so we pretend).
  // };
  OpaqueType *RecursiveTy = OpaqueType::get();
  
  EltTys.clear();
  EltTys.push_back(PointerType::getUnqual(RecursiveTy));
  EltTys.push_back(FrameMapPtrTy);
  PATypeHolder LinkTyH = StructType::get(EltTys);
  
  RecursiveTy->refineAbstractTypeTo(LinkTyH.get());
  StackEntryTy = cast<StructType>(LinkTyH.get());
  const PointerType *StackEntryPtrTy = PointerType::getUnqual(StackEntryTy);
  M.addTypeName("gc_stackentry", LinkTyH.get());  // FIXME: Is this safe from
                                                  //        a FunctionPass?
  
  // Get the root chain if it already exists.
  Head = M.getGlobalVariable("llvm_gc_root_chain");
  if (!Head) {
    // If the root chain does not exist, insert a new one with linkonce
    // linkage!
    Head = new GlobalVariable(StackEntryPtrTy, false,
                              GlobalValue::LinkOnceLinkage,
                              Constant::getNullValue(StackEntryPtrTy),
                              "llvm_gc_root_chain", &M);
  } else if (Head->hasExternalLinkage() && Head->isDeclaration()) {
    Head->setInitializer(Constant::getNullValue(StackEntryPtrTy));
    Head->setLinkage(GlobalValue::LinkOnceLinkage);
  }
  
  return true;
}

bool ShadowStackCollector::IsNullValue(Value *V) {
  if (Constant *C = dyn_cast<Constant>(V))
    return C->isNullValue();
  return false;
}

void ShadowStackCollector::CollectRoots(Function &F) {
  // FIXME: Account for original alignment. Could fragment the root array.
  //   Approach 1: Null initialize empty slots at runtime. Yuck.
  //   Approach 2: Emit a map of the array instead of just a count.
  
  assert(Roots.empty() && "Not cleaned up?");
  
  SmallVector<std::pair<CallInst*,AllocaInst*>,16> MetaRoots;
  
  for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
    for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;)
      if (IntrinsicInst *CI = dyn_cast<IntrinsicInst>(II++))
        if (Function *F = CI->getCalledFunction())
          if (F->getIntrinsicID() == Intrinsic::gcroot) {
            std::pair<CallInst*,AllocaInst*> Pair = std::make_pair(
              CI, cast<AllocaInst>(
                    IntrinsicInst::StripPointerCasts(CI->getOperand(1))));
            if (IsNullValue(CI->getOperand(2)))
              Roots.push_back(Pair);
            else
              MetaRoots.push_back(Pair);
          }
  
  // Number roots with metadata (usually empty) at the beginning, so that the
  // FrameMap::Meta array can be elided.
  Roots.insert(Roots.begin(), MetaRoots.begin(), MetaRoots.end());
}

GetElementPtrInst *
ShadowStackCollector::CreateGEP(LLVMBuilder &B, Value *BasePtr,
                                int Idx, int Idx2, const char *Name) {
  Value *Indices[] = { ConstantInt::get(Type::Int32Ty, 0),
                       ConstantInt::get(Type::Int32Ty, Idx),
                       ConstantInt::get(Type::Int32Ty, Idx2) };
  return B.CreateGEP(BasePtr, Indices, Indices + 3, Name);
}

GetElementPtrInst *
ShadowStackCollector::CreateGEP(LLVMBuilder &B, Value *BasePtr,
                                int Idx, const char *Name) {
  Value *Indices[] = { ConstantInt::get(Type::Int32Ty, 0),
                       ConstantInt::get(Type::Int32Ty, Idx) };
  return B.CreateGEP(BasePtr, Indices, Indices + 2, Name);
}

/// runOnFunction - Insert code to maintain the shadow stack.
bool ShadowStackCollector::performCustomLowering(Function &F) {
  // Find calls to llvm.gcroot.
  CollectRoots(F);
  
  // If there are no roots in this function, then there is no need to add a
  // stack map entry for it.
  if (Roots.empty())
    return false;
  
  // Build the constant map and figure the type of the shadow stack entry.
  Value *FrameMap = GetFrameMap(F);
  const Type *ConcreteStackEntryTy = GetConcreteStackEntryType(F);
  
  // Build the shadow stack entry at the very start of the function.
  BasicBlock::iterator IP = F.getEntryBlock().begin();
  LLVMBuilder AtEntry(IP->getParent(), IP);
  
  Instruction *StackEntry   = AtEntry.CreateAlloca(ConcreteStackEntryTy, 0,
                                                   "gc_frame");
  
  while (isa<AllocaInst>(IP)) ++IP;
  AtEntry.SetInsertPoint(IP->getParent(), IP);
  
  // Initialize the map pointer and load the current head of the shadow stack.
  Instruction *CurrentHead  = AtEntry.CreateLoad(Head, "gc_currhead");
  Instruction *EntryMapPtr  = CreateGEP(AtEntry, StackEntry,0,1,"gc_frame.map");
                              AtEntry.CreateStore(FrameMap, EntryMapPtr);
  
  // After all the allocas...
  for (unsigned I = 0, E = Roots.size(); I != E; ++I) {
    // For each root, find the corresponding slot in the aggregate...
    Value *SlotPtr = CreateGEP(AtEntry, StackEntry, 1 + I, "gc_root");
    
    // And use it in lieu of the alloca.
    AllocaInst *OriginalAlloca = Roots[I].second;
    SlotPtr->takeName(OriginalAlloca);
    OriginalAlloca->replaceAllUsesWith(SlotPtr);
  }
  
  // Move past the original stores inserted by Collector::InitRoots. This isn't
  // really necessary (the collector would never see the intermediate state),
  // but it's nicer not to push the half-initialized entry onto the stack.
  while (isa<StoreInst>(IP)) ++IP;
  AtEntry.SetInsertPoint(IP->getParent(), IP);
  
  // Push the entry onto the shadow stack.
  Instruction *EntryNextPtr = CreateGEP(AtEntry,StackEntry,0,0,"gc_frame.next");
  Instruction *NewHeadVal   = CreateGEP(AtEntry,StackEntry, 0, "gc_newhead");
                              AtEntry.CreateStore(CurrentHead, EntryNextPtr);
                              AtEntry.CreateStore(NewHeadVal, Head);
  
  // For each instruction that escapes...
  EscapeEnumerator EE(F, "gc_cleanup");
  while (LLVMBuilder *AtExit = EE.Next()) {
    // Pop the entry from the shadow stack. Don't reuse CurrentHead from
    // AtEntry, since that would make the value live for the entire function.
    Instruction *EntryNextPtr2 = CreateGEP(*AtExit, StackEntry, 0, 0,
                                           "gc_frame.next");
    Value *SavedHead = AtExit->CreateLoad(EntryNextPtr2, "gc_savedhead");
                       AtExit->CreateStore(SavedHead, Head);
  }
  
  // Delete the original allocas (which are no longer used) and the intrinsic
  // calls (which are no longer valid). Doing this last avoids invalidating
  // iterators.
  for (unsigned I = 0, E = Roots.size(); I != E; ++I) {
    Roots[I].first->eraseFromParent();
    Roots[I].second->eraseFromParent();
  }
  
  Roots.clear();
  return true;
}