CrashDebugger.cpp revision f607b79bc78fcbfd8cda01d2d5dbda6cd8253a40
1//===- CrashDebugger.cpp - Debug compilation crashes ----------------------===// 2// 3// This file defines the bugpoint internals that narrow down compilation crashes 4// 5//===----------------------------------------------------------------------===// 6 7#include "BugDriver.h" 8#include "SystemUtils.h" 9#include "ListReducer.h" 10#include "llvm/Module.h" 11#include "llvm/Transforms/Utils/Cloning.h" 12#include "llvm/Bytecode/Writer.h" 13#include "llvm/Pass.h" 14#include <fstream> 15#include <set> 16 17class DebugCrashes : public ListReducer<const PassInfo*> { 18 BugDriver &BD; 19public: 20 DebugCrashes(BugDriver &bd) : BD(bd) {} 21 22 // doTest - Return true iff running the "removed" passes succeeds, and running 23 // the "Kept" passes fail when run on the output of the "removed" passes. If 24 // we return true, we update the current module of bugpoint. 25 // 26 virtual TestResult doTest(std::vector<const PassInfo*> &Removed, 27 std::vector<const PassInfo*> &Kept); 28}; 29 30DebugCrashes::TestResult 31DebugCrashes::doTest(std::vector<const PassInfo*> &Prefix, 32 std::vector<const PassInfo*> &Suffix) { 33 std::string PrefixOutput; 34 if (!Prefix.empty()) { 35 std::cout << "Checking to see if these passes crash: " 36 << getPassesString(Prefix) << ": "; 37 if (BD.runPasses(Prefix, PrefixOutput)) 38 return KeepPrefix; 39 } 40 41 std::cout << "Checking to see if these passes crash: " 42 << getPassesString(Suffix) << ": "; 43 Module *OrigProgram = BD.Program; 44 BD.Program = BD.ParseInputFile(PrefixOutput); 45 if (BD.Program == 0) { 46 std::cerr << BD.getToolName() << ": Error reading bytecode file '" 47 << PrefixOutput << "'!\n"; 48 exit(1); 49 } 50 removeFile(PrefixOutput); 51 52 if (BD.runPasses(Suffix)) { 53 delete OrigProgram; // The suffix crashes alone... 54 return KeepSuffix; 55 } 56 57 // Nothing failed, restore state... 58 delete BD.Program; 59 BD.Program = OrigProgram; 60 return NoFailure; 61} 62 63class ReduceCrashingFunctions : public ListReducer<Function*> { 64 BugDriver &BD; 65public: 66 ReduceCrashingFunctions(BugDriver &bd) : BD(bd) {} 67 68 virtual TestResult doTest(std::vector<Function*> &Prefix, 69 std::vector<Function*> &Kept) { 70 if (TestFuncs(Kept)) 71 return KeepSuffix; 72 if (!Prefix.empty() && TestFuncs(Prefix)) 73 return KeepPrefix; 74 return NoFailure; 75 } 76 77 bool TestFuncs(std::vector<Function*> &Prefix); 78}; 79 80bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { 81 // Clone the program to try hacking it appart... 82 Module *M = CloneModule(BD.Program); 83 84 // Convert list to set for fast lookup... 85 std::set<Function*> Functions; 86 for (unsigned i = 0, e = Funcs.size(); i != e; ++i) { 87 Function *CMF = M->getFunction(Funcs[i]->getName(), 88 Funcs[i]->getFunctionType()); 89 assert(CMF && "Function not in module?!"); 90 Functions.insert(CMF); 91 } 92 93 std::cout << "Checking for crash with only these functions:"; 94 for (unsigned i = 0, e = Funcs.size(); i != e; ++i) 95 std::cout << " " << Funcs[i]->getName(); 96 std::cout << ": "; 97 98 // Loop over and delete any functions which we aren't supposed to be playing 99 // with... 100 for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) 101 if (!I->isExternal() && !Functions.count(I)) 102 DeleteFunctionBody(I); 103 104 // Try running the hacked up program... 105 std::swap(BD.Program, M); 106 if (BD.runPasses(BD.PassesToRun)) { 107 delete M; // It crashed, keep the trimmed version... 108 109 // Make sure to use function pointers that point into the now-current 110 // module. 111 Funcs.assign(Functions.begin(), Functions.end()); 112 return true; 113 } 114 delete BD.Program; // It didn't crash, revert... 115 BD.Program = M; 116 return false; 117} 118 119 120/// debugCrash - This method is called when some pass crashes on input. It 121/// attempts to prune down the testcase to something reasonable, and figure 122/// out exactly which pass is crashing. 123/// 124bool BugDriver::debugCrash() { 125 bool AnyReduction = false; 126 std::cout << "\n*** Debugging optimizer crash!\n"; 127 128 // Reduce the list of passes which causes the optimizer to crash... 129 unsigned OldSize = PassesToRun.size(); 130 DebugCrashes(*this).reduceList(PassesToRun); 131 132 std::cout << "\n*** Found crashing pass" 133 << (PassesToRun.size() == 1 ? ": " : "es: ") 134 << getPassesString(PassesToRun) << "\n"; 135 136 EmitProgressBytecode("passinput"); 137 138 // Now try to reduce the number of functions in the module to something small. 139 std::vector<Function*> Functions; 140 for (Module::iterator I = Program->begin(), E = Program->end(); I != E; ++I) 141 if (!I->isExternal()) 142 Functions.push_back(I); 143 144 if (Functions.size() > 1) { 145 std::cout << "\n*** Attempting to reduce the number of functions " 146 "in the testcase\n"; 147 148 OldSize = Functions.size(); 149 ReduceCrashingFunctions(*this).reduceList(Functions); 150 151 if (Functions.size() < OldSize) { 152 EmitProgressBytecode("reduced-function"); 153 AnyReduction = true; 154 } 155 } 156 157 // FIXME: This should attempt to delete entire basic blocks at a time to speed 158 // up convergence... 159 160 // FIXME: This should use the list reducer to converge faster by deleting 161 // larger chunks of instructions at a time! 162 unsigned Simplification = 4; 163 do { 164 --Simplification; 165 std::cout << "\n*** Attempting to reduce testcase by deleting instruc" 166 << "tions: Simplification Level #" << Simplification << "\n"; 167 168 // Now that we have deleted the functions that are unneccesary for the 169 // program, try to remove instructions that are not neccesary to cause the 170 // crash. To do this, we loop through all of the instructions in the 171 // remaining functions, deleting them (replacing any values produced with 172 // nulls), and then running ADCE and SimplifyCFG. If the transformed input 173 // still triggers failure, keep deleting until we cannot trigger failure 174 // anymore. 175 // 176 TryAgain: 177 178 // Loop over all of the (non-terminator) instructions remaining in the 179 // function, attempting to delete them. 180 for (Module::iterator FI = Program->begin(), E = Program->end(); 181 FI != E; ++FI) 182 if (!FI->isExternal()) { 183 for (Function::iterator BI = FI->begin(), E = FI->end(); BI != E; ++BI) 184 for (BasicBlock::iterator I = BI->begin(), E = --BI->end(); 185 I != E; ++I) { 186 Module *M = deleteInstructionFromProgram(I, Simplification); 187 188 // Make the function the current program... 189 std::swap(Program, M); 190 191 // Find out if the pass still crashes on this pass... 192 std::cout << "Checking instruction '" << I->getName() << "': "; 193 if (runPasses(PassesToRun)) { 194 // Yup, it does, we delete the old module, and continue trying to 195 // reduce the testcase... 196 delete M; 197 AnyReduction = true; 198 goto TryAgain; // I wish I had a multi-level break here! 199 } 200 201 // This pass didn't crash without this instruction, try the next 202 // one. 203 delete Program; 204 Program = M; 205 } 206 } 207 } while (Simplification); 208 209 // Try to clean up the testcase by running funcresolve and globaldce... 210 if (AnyReduction) { 211 std::cout << "\n*** Attempting to perform final cleanups: "; 212 Module *M = performFinalCleanups(); 213 std::swap(Program, M); 214 215 // Find out if the pass still crashes on the cleaned up program... 216 if (runPasses(PassesToRun)) { 217 // Yup, it does, keep the reduced version... 218 delete M; 219 AnyReduction = true; 220 } else { 221 delete Program; // Otherwise, restore the original module... 222 Program = M; 223 } 224 } 225 226 if (AnyReduction) 227 EmitProgressBytecode("reduced-simplified"); 228 229 return false; 230} 231