LLVM API Documentation

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

TraceValues.cpp

Go to the documentation of this file.
00001 //===- TraceValues.cpp - Value Tracing for debugging ----------------------===//
00002 // 
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file was developed by the LLVM research group and is distributed under
00006 // the University of Illinois Open Source License. See LICENSE.TXT for details.
00007 // 
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // Support for inserting LLVM code to print values at basic block and function
00011 // exits.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "llvm/Transforms/Instrumentation.h"
00016 #include "llvm/Constants.h"
00017 #include "llvm/DerivedTypes.h"
00018 #include "llvm/Instructions.h"
00019 #include "llvm/Module.h"
00020 #include "llvm/Pass.h"
00021 #include "llvm/Assembly/Writer.h"
00022 #include "llvm/Support/CommandLine.h"
00023 #include "llvm/ADT/StringExtras.h"
00024 #include <algorithm>
00025 #include <sstream>
00026 using namespace llvm;
00027 
00028 static cl::opt<bool>
00029 DisablePtrHashing("tracedisablehashdisable", cl::Hidden,
00030                   cl::desc("Disable pointer hashing in the -trace or -tracem "
00031                            "passes"));
00032 
00033 static cl::list<std::string>
00034 TraceFuncNames("tracefunc", cl::desc("Only trace specific functions in the "
00035                                      "-trace or -tracem passes"),
00036          cl::value_desc("function"), cl::Hidden);
00037 
00038 static void TraceValuesAtBBExit(BasicBlock *BB,
00039                                 Function *Printf, Function* HashPtrToSeqNum,
00040                              std::vector<Instruction*> *valuesStoredInFunction);
00041 
00042 // We trace a particular function if no functions to trace were specified
00043 // or if the function is in the specified list.
00044 // 
00045 inline static bool
00046 TraceThisFunction(Function &F)
00047 {
00048   if (TraceFuncNames.empty()) return true;
00049 
00050   return std::find(TraceFuncNames.begin(), TraceFuncNames.end(), F.getName())
00051                   != TraceFuncNames.end();
00052 }
00053 
00054 
00055 namespace {
00056   struct ExternalFuncs {
00057     Function *PrintfFunc, *HashPtrFunc, *ReleasePtrFunc;
00058     Function *RecordPtrFunc, *PushOnEntryFunc, *ReleaseOnReturnFunc;
00059     void doInitialization(Module &M); // Add prototypes for external functions
00060   };
00061   
00062   class InsertTraceCode : public FunctionPass {
00063   protected:
00064     ExternalFuncs externalFuncs;
00065   public:
00066     
00067     // Add a prototype for runtime functions not already in the program.
00068     //
00069     bool doInitialization(Module &M);
00070     
00071     //--------------------------------------------------------------------------
00072     // Function InsertCodeToTraceValues
00073     // 
00074     // Inserts tracing code for all live values at basic block and/or function
00075     // exits as specified by `traceBasicBlockExits' and `traceFunctionExits'.
00076     //
00077     bool doit(Function *M);
00078 
00079     virtual void handleBasicBlock(BasicBlock *BB,
00080                                   std::vector<Instruction*> &VI) = 0;
00081 
00082     // runOnFunction - This method does the work.
00083     //
00084     bool runOnFunction(Function &F);
00085 
00086     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
00087       AU.setPreservesCFG();
00088     }
00089   };
00090 
00091   struct FunctionTracer : public InsertTraceCode {
00092     // Ignore basic blocks here...
00093     virtual void handleBasicBlock(BasicBlock *BB,
00094                                   std::vector<Instruction*> &VI) {}
00095   };
00096 
00097   struct BasicBlockTracer : public InsertTraceCode {
00098     // Trace basic blocks here...
00099     virtual void handleBasicBlock(BasicBlock *BB,
00100                                   std::vector<Instruction*> &VI) {
00101       TraceValuesAtBBExit(BB, externalFuncs.PrintfFunc,
00102                           externalFuncs.HashPtrFunc, &VI);
00103     }
00104   };
00105 
00106   // Register the passes...
00107   RegisterOpt<FunctionTracer>  X("tracem","Insert Function trace code only");
00108   RegisterOpt<BasicBlockTracer> Y("trace","Insert BB and Function trace code");
00109 } // end anonymous namespace
00110 
00111 /// Just trace functions
00112 FunctionPass *llvm::createTraceValuesPassForFunction() {
00113   return new FunctionTracer();
00114 }
00115 
00116 /// Trace BB's and functions
00117 FunctionPass *llvm::createTraceValuesPassForBasicBlocks() {
00118   return new BasicBlockTracer();
00119 }
00120 
00121 // Add a prototype for external functions used by the tracing code.
00122 //
00123 void ExternalFuncs::doInitialization(Module &M) {
00124   const Type *SBP = PointerType::get(Type::SByteTy);
00125   const FunctionType *MTy =
00126     FunctionType::get(Type::IntTy, std::vector<const Type*>(1, SBP), true);
00127   PrintfFunc = M.getOrInsertFunction("printf", MTy);
00128 
00129   // uint (sbyte*)
00130   HashPtrFunc = M.getOrInsertFunction("HashPointerToSeqNum", Type::UIntTy, SBP,
00131                                       0);
00132   
00133   // void (sbyte*)
00134   ReleasePtrFunc = M.getOrInsertFunction("ReleasePointerSeqNum", 
00135                                          Type::VoidTy, SBP, 0);
00136   RecordPtrFunc  = M.getOrInsertFunction("RecordPointer",
00137                                          Type::VoidTy, SBP, 0);
00138   
00139   PushOnEntryFunc = M.getOrInsertFunction("PushPointerSet", Type::VoidTy, 0);
00140   ReleaseOnReturnFunc = M.getOrInsertFunction("ReleasePointersPopSet",
00141                                               Type::VoidTy, 0);
00142 }
00143 
00144 
00145 // Add a prototype for external functions used by the tracing code.
00146 //
00147 bool InsertTraceCode::doInitialization(Module &M) {
00148   externalFuncs.doInitialization(M);
00149   return false;
00150 }
00151 
00152 
00153 static inline GlobalVariable *getStringRef(Module *M, const std::string &str) {
00154   // Create a constant internal string reference...
00155   Constant *Init = ConstantArray::get(str);
00156 
00157   // Create the global variable and record it in the module
00158   // The GV will be renamed to a unique name if needed.
00159   GlobalVariable *GV = new GlobalVariable(Init->getType(), true, 
00160                                           GlobalValue::InternalLinkage, Init,
00161                                           "trstr");
00162   M->getGlobalList().push_back(GV);
00163   return GV;
00164 }
00165 
00166 
00167 // 
00168 // Check if this instruction has any uses outside its basic block,
00169 // or if it used by either a Call or Return instruction (ditto).
00170 // (Values stored to memory within this BB are live at end of BB but are
00171 // traced at the store instruction, not where they are computed.)
00172 // 
00173 static inline bool LiveAtBBExit(const Instruction* I) {
00174   const BasicBlock *BB = I->getParent();
00175   for (Value::use_const_iterator U = I->use_begin(); U != I->use_end(); ++U)
00176     if (const Instruction *UI = dyn_cast<Instruction>(*U))
00177       if (UI->getParent() != BB || isa<ReturnInst>(UI))
00178         return true;
00179 
00180   return false;
00181 }
00182 
00183 
00184 static inline bool TraceThisOpCode(unsigned opCode) {
00185   // Explicitly test for opCodes *not* to trace so that any new opcodes will
00186   // be traced by default (VoidTy's are already excluded)
00187   // 
00188   return (opCode  < Instruction::OtherOpsBegin &&
00189           opCode != Instruction::Alloca &&
00190           opCode != Instruction::PHI &&
00191           opCode != Instruction::Cast);
00192 }
00193 
00194 
00195 // Trace a value computed by an instruction if it is non-void, it is computed
00196 // by a real computation, not just a copy (see TraceThisOpCode), and
00197 // -- it is a load instruction: we want to check values read from memory
00198 // -- or it is live at exit from the basic block (i.e., ignore local temps)
00199 // 
00200 static bool ShouldTraceValue(const Instruction *I) {
00201   return
00202     I->getType() != Type::VoidTy &&
00203     TraceThisOpCode(I->getOpcode()) &&
00204     (isa<LoadInst>(I) || LiveAtBBExit(I));
00205 }
00206 
00207 static std::string getPrintfCodeFor(const Value *V) {
00208   if (V == 0) return "";
00209   if (V->getType()->isFloatingPoint())
00210     return "%g";
00211   else if (V->getType() == Type::LabelTy)
00212     return "0x%p";
00213   else if (isa<PointerType>(V->getType()))
00214     return DisablePtrHashing ? "0x%p" : "%d";
00215   else if (V->getType()->isIntegral())
00216     return "%d";
00217   
00218   assert(0 && "Illegal value to print out...");
00219   return "";
00220 }
00221 
00222 
00223 static void InsertPrintInst(Value *V, BasicBlock *BB, Instruction *InsertBefore,
00224                             std::string Message,
00225                             Function *Printf, Function* HashPtrToSeqNum) {
00226   // Escape Message by replacing all % characters with %% chars.
00227   std::string Tmp;
00228   std::swap(Tmp, Message);
00229   std::string::iterator I = std::find(Tmp.begin(), Tmp.end(), '%');
00230   while (I != Tmp.end()) {
00231     Message.append(Tmp.begin(), I);
00232     Message += "%%";
00233     ++I; // Make sure to erase the % as well...
00234     Tmp.erase(Tmp.begin(), I);
00235     I = std::find(Tmp.begin(), Tmp.end(), '%');
00236   }
00237   Message += Tmp;
00238   Module *Mod = BB->getParent()->getParent();
00239 
00240   // Turn the marker string into a global variable...
00241   GlobalVariable *fmtVal = getStringRef(Mod, Message+getPrintfCodeFor(V)+"\n");
00242 
00243   // Turn the format string into an sbyte *
00244   Constant *GEP=ConstantExpr::getGetElementPtr(fmtVal,
00245                 std::vector<Constant*>(2,Constant::getNullValue(Type::LongTy)));
00246   
00247   // Insert a call to the hash function if this is a pointer value
00248   if (V && isa<PointerType>(V->getType()) && !DisablePtrHashing) {
00249     const Type *SBP = PointerType::get(Type::SByteTy);
00250     if (V->getType() != SBP)     // Cast pointer to be sbyte*
00251       V = new CastInst(V, SBP, "Hash_cast", InsertBefore);
00252 
00253     std::vector<Value*> HashArgs(1, V);
00254     V = new CallInst(HashPtrToSeqNum, HashArgs, "ptrSeqNum", InsertBefore);
00255   }
00256   
00257   // Insert the first print instruction to print the string flag:
00258   std::vector<Value*> PrintArgs;
00259   PrintArgs.push_back(GEP);
00260   if (V) PrintArgs.push_back(V);
00261   new CallInst(Printf, PrintArgs, "trace", InsertBefore);
00262 }
00263                             
00264 
00265 static void InsertVerbosePrintInst(Value *V, BasicBlock *BB,
00266                                    Instruction *InsertBefore,
00267                                    const std::string &Message, Function *Printf,
00268                                    Function* HashPtrToSeqNum) {
00269   std::ostringstream OutStr;
00270   if (V) WriteAsOperand(OutStr, V);
00271   InsertPrintInst(V, BB, InsertBefore, Message+OutStr.str()+" = ",
00272                   Printf, HashPtrToSeqNum);
00273 }
00274 
00275 static void 
00276 InsertReleaseInst(Value *V, BasicBlock *BB,
00277                   Instruction *InsertBefore,
00278                   Function* ReleasePtrFunc) {
00279   
00280   const Type *SBP = PointerType::get(Type::SByteTy);
00281   if (V->getType() != SBP)    // Cast pointer to be sbyte*
00282     V = new CastInst(V, SBP, "RPSN_cast", InsertBefore);
00283 
00284   std::vector<Value*> releaseArgs(1, V);
00285   new CallInst(ReleasePtrFunc, releaseArgs, "", InsertBefore);
00286 }
00287 
00288 static void 
00289 InsertRecordInst(Value *V, BasicBlock *BB,
00290                  Instruction *InsertBefore,
00291                  Function* RecordPtrFunc) {
00292     const Type *SBP = PointerType::get(Type::SByteTy);
00293   if (V->getType() != SBP)     // Cast pointer to be sbyte*
00294     V = new CastInst(V, SBP, "RP_cast", InsertBefore);
00295 
00296   std::vector<Value*> releaseArgs(1, V);
00297   new CallInst(RecordPtrFunc, releaseArgs, "", InsertBefore);
00298 }
00299 
00300 // Look for alloca and free instructions. These are the ptrs to release.
00301 // Release the free'd pointers immediately.  Record the alloca'd pointers
00302 // to be released on return from the current function.
00303 // 
00304 static void
00305 ReleasePtrSeqNumbers(BasicBlock *BB,
00306                      ExternalFuncs& externalFuncs) {
00307   
00308   for (BasicBlock::iterator II=BB->begin(), IE = BB->end(); II != IE; ++II)
00309     if (FreeInst *FI = dyn_cast<FreeInst>(II))
00310       InsertReleaseInst(FI->getOperand(0), BB, FI,externalFuncs.ReleasePtrFunc);
00311     else if (AllocaInst *AI = dyn_cast<AllocaInst>(II))
00312       InsertRecordInst(AI, BB, AI->getNext(), externalFuncs.RecordPtrFunc);
00313 }  
00314 
00315 
00316 // Insert print instructions at the end of basic block BB for each value
00317 // computed in BB that is live at the end of BB,
00318 // or that is stored to memory in BB.
00319 // If the value is stored to memory, we load it back before printing it
00320 // We also return all such loaded values in the vector valuesStoredInFunction
00321 // for printing at the exit from the function.  (Note that in each invocation
00322 // of the function, this will only get the last value stored for each static
00323 // store instruction).
00324 // 
00325 static void TraceValuesAtBBExit(BasicBlock *BB,
00326                                 Function *Printf, Function* HashPtrToSeqNum,
00327                             std::vector<Instruction*> *valuesStoredInFunction) {
00328   // Get an iterator to point to the insertion location, which is
00329   // just before the terminator instruction.
00330   // 
00331   TerminatorInst *InsertPos = BB->getTerminator();
00332   
00333   std::ostringstream OutStr;
00334   WriteAsOperand(OutStr, BB, false);
00335   InsertPrintInst(0, BB, InsertPos, "LEAVING BB:" + OutStr.str(),
00336                   Printf, HashPtrToSeqNum);
00337 
00338   // Insert a print instruction for each instruction preceding InsertPos.
00339   // The print instructions must go before InsertPos, so we use the
00340   // instruction *preceding* InsertPos to check when to terminate the loop.
00341   // 
00342   for (BasicBlock::iterator II = BB->begin(); &*II != InsertPos; ++II) {
00343     if (StoreInst *SI = dyn_cast<StoreInst>(II)) {
00344       // Trace the stored value and address
00345       InsertVerbosePrintInst(SI->getOperand(0), BB, InsertPos,
00346                              "  (store value) ", Printf, HashPtrToSeqNum);
00347       InsertVerbosePrintInst(SI->getOperand(1), BB, InsertPos,
00348                              "  (store addr ) ", Printf, HashPtrToSeqNum);
00349     }
00350     else if (ShouldTraceValue(II))
00351       InsertVerbosePrintInst(II, BB, InsertPos, "  ", Printf, HashPtrToSeqNum);
00352   }
00353 }
00354 
00355 static inline void InsertCodeToShowFunctionEntry(Function &F, Function *Printf,
00356                                                  Function* HashPtrToSeqNum){
00357   // Get an iterator to point to the insertion location
00358   BasicBlock &BB = F.getEntryBlock();
00359   Instruction *InsertPos = BB.begin();
00360 
00361   std::ostringstream OutStr;
00362   WriteAsOperand(OutStr, &F);
00363   InsertPrintInst(0, &BB, InsertPos, "ENTERING FUNCTION: " + OutStr.str(),
00364                   Printf, HashPtrToSeqNum);
00365 
00366   // Now print all the incoming arguments
00367   unsigned ArgNo = 0;
00368   for (Function::aiterator I = F.abegin(), E = F.aend(); I != E; ++I, ++ArgNo){
00369     InsertVerbosePrintInst(I, &BB, InsertPos,
00370                            "  Arg #" + utostr(ArgNo) + ": ", Printf,
00371                            HashPtrToSeqNum);
00372   }
00373 }
00374 
00375 
00376 static inline void InsertCodeToShowFunctionExit(BasicBlock *BB,
00377                                                 Function *Printf,
00378                                                 Function* HashPtrToSeqNum) {
00379   // Get an iterator to point to the insertion location
00380   ReturnInst *Ret = cast<ReturnInst>(BB->getTerminator());
00381   
00382   std::ostringstream OutStr;
00383   WriteAsOperand(OutStr, BB->getParent(), true);
00384   InsertPrintInst(0, BB, Ret, "LEAVING  FUNCTION: " + OutStr.str(),
00385                   Printf, HashPtrToSeqNum);
00386   
00387   // print the return value, if any
00388   if (BB->getParent()->getReturnType() != Type::VoidTy)
00389     InsertPrintInst(Ret->getReturnValue(), BB, Ret, "  Returning: ",
00390                     Printf, HashPtrToSeqNum);
00391 }
00392 
00393 
00394 bool InsertTraceCode::runOnFunction(Function &F) {
00395   if (!TraceThisFunction(F))
00396     return false;
00397   
00398   std::vector<Instruction*> valuesStoredInFunction;
00399   std::vector<BasicBlock*>  exitBlocks;
00400 
00401   // Insert code to trace values at function entry
00402   InsertCodeToShowFunctionEntry(F, externalFuncs.PrintfFunc,
00403                                 externalFuncs.HashPtrFunc);
00404   
00405   // Push a pointer set for recording alloca'd pointers at entry.
00406   if (!DisablePtrHashing)
00407     new CallInst(externalFuncs.PushOnEntryFunc, std::vector<Value*>(), "",
00408                  F.getEntryBlock().begin());
00409 
00410   for (Function::iterator BB = F.begin(); BB != F.end(); ++BB) {
00411     if (isa<ReturnInst>(BB->getTerminator()))
00412       exitBlocks.push_back(BB); // record this as an exit block
00413 
00414     // Insert trace code if this basic block is interesting...
00415     handleBasicBlock(BB, valuesStoredInFunction);
00416 
00417     if (!DisablePtrHashing)          // release seq. numbers on free/ret
00418       ReleasePtrSeqNumbers(BB, externalFuncs);
00419   }
00420   
00421   for (unsigned i=0; i != exitBlocks.size(); ++i)
00422     {
00423       // Insert code to trace values at function exit
00424       InsertCodeToShowFunctionExit(exitBlocks[i], externalFuncs.PrintfFunc,
00425                                    externalFuncs.HashPtrFunc);
00426       
00427       // Release all recorded pointers before RETURN.  Do this LAST!
00428       if (!DisablePtrHashing)
00429         new CallInst(externalFuncs.ReleaseOnReturnFunc, std::vector<Value*>(),
00430                      "", exitBlocks[i]->getTerminator());
00431     }
00432   
00433   return true;
00434 }