diff options
author | Djordje Todorovic <djtodoro@cisco.com> | 2021-02-22 06:01:54 -0800 |
---|---|---|
committer | Djordje Todorovic <djtodoro@cisco.com> | 2021-03-11 01:11:13 -0800 |
commit | 9f41c03f82874075c30b97b8ff71eff70f313fa0 (patch) | |
tree | 03cc3def5860163ce95884f7c4b19e4478d55d5b /llvm/lib/Transforms/Utils/Debugify.cpp | |
parent | b975e3b5aa8c6c8b608302997a3bf0fda06bf8d8 (diff) | |
download | llvm-9f41c03f82874075c30b97b8ff71eff70f313fa0.zip llvm-9f41c03f82874075c30b97b8ff71eff70f313fa0.tar.gz llvm-9f41c03f82874075c30b97b8ff71eff70f313fa0.tar.bz2 |
[Debugify][OriginalDIMode] Export the report into JSON file
By using the original-di check with debugify in the combination with
the llvm/utils/llvm-original-di-preservation.py it becomes very user
friendly tool. An example of the HTML page with the issues
related to debug info can be found at [0].
[0] https://djolertrk.github.io/di-checker-html-report-example/
Differential Revision: https://reviews.llvm.org/D82546
Diffstat (limited to 'llvm/lib/Transforms/Utils/Debugify.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/Debugify.cpp | 134 |
1 files changed, 104 insertions, 30 deletions
diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp index 7e6ce8c..73a3a40 100644 --- a/llvm/lib/Transforms/Utils/Debugify.cpp +++ b/llvm/lib/Transforms/Utils/Debugify.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/PassInstrumentation.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/JSON.h" #define DEBUG_TYPE "debugify" @@ -334,16 +335,22 @@ bool llvm::collectDebugInfoMetadata(Module &M, static bool checkFunctions(const DebugFnMap &DIFunctionsBefore, const DebugFnMap &DIFunctionsAfter, StringRef NameOfWrappedPass, - StringRef FileNameFromCU) { + StringRef FileNameFromCU, bool ShouldWriteIntoJSON, + llvm::json::Array &Bugs) { bool Preserved = true; for (const auto &F : DIFunctionsAfter) { if (F.second) continue; auto SPIt = DIFunctionsBefore.find(F.first); if (SPIt == DIFunctionsBefore.end()) { - dbg() << "ERROR: " << NameOfWrappedPass - << " did not generate DISubprogram for " << F.first << " from " - << FileNameFromCU << '\n'; + if (ShouldWriteIntoJSON) + Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"}, + {"name", F.first}, + {"action", "not-generate"}})); + else + dbg() << "ERROR: " << NameOfWrappedPass + << " did not generate DISubprogram for " << F.first << " from " + << FileNameFromCU << '\n'; Preserved = false; } else { auto SP = SPIt->second; @@ -351,8 +358,13 @@ static bool checkFunctions(const DebugFnMap &DIFunctionsBefore, continue; // If the function had the SP attached before the pass, consider it as // a debug info bug. - dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of " - << F.first << " from " << FileNameFromCU << '\n'; + if (ShouldWriteIntoJSON) + Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"}, + {"name", F.first}, + {"action", "drop"}})); + else + dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of " + << F.first << " from " << FileNameFromCU << '\n'; Preserved = false; } } @@ -366,7 +378,9 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore, const DebugInstMap &DILocsAfter, const WeakInstValueMap &InstToDelete, StringRef NameOfWrappedPass, - StringRef FileNameFromCU) { + StringRef FileNameFromCU, + bool ShouldWriteIntoJSON, + llvm::json::Array &Bugs) { bool Preserved = true; for (const auto &L : DILocsAfter) { if (L.second) @@ -382,22 +396,37 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore, auto FnName = Instr->getFunction()->getName(); auto BB = Instr->getParent(); auto BBName = BB->hasName() ? BB->getName() : "no-name"; + auto InstName = Instruction::getOpcodeName(Instr->getOpcode()); auto InstrIt = DILocsBefore.find(Instr); if (InstrIt == DILocsBefore.end()) { - dbg() << "WARNING: " << NameOfWrappedPass - << " did not generate DILocation for " << *Instr - << " (BB: " << BBName << ", Fn: " << FnName - << ", File: " << FileNameFromCU << ")\n"; + if (ShouldWriteIntoJSON) + Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"}, + {"fn-name", FnName.str()}, + {"bb-name", BBName.str()}, + {"instr", InstName}, + {"action", "not-generate"}})); + else + dbg() << "WARNING: " << NameOfWrappedPass + << " did not generate DILocation for " << *Instr + << " (BB: " << BBName << ", Fn: " << FnName + << ", File: " << FileNameFromCU << ")\n"; Preserved = false; } else { if (!InstrIt->second) continue; // If the instr had the !dbg attached before the pass, consider it as // a debug info issue. - dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of " - << *Instr << " (BB: " << BBName << ", Fn: " << FnName - << ", File: " << FileNameFromCU << ")\n"; + if (ShouldWriteIntoJSON) + Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"}, + {"fn-name", FnName.str()}, + {"bb-name", BBName.str()}, + {"instr", InstName}, + {"action", "drop"}})); + else + dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of " + << *Instr << " (BB: " << BBName << ", Fn: " << FnName + << ", File: " << FileNameFromCU << ")\n"; Preserved = false; } } @@ -405,11 +434,35 @@ static bool checkInstructions(const DebugInstMap &DILocsBefore, return Preserved; } +// Write the json data into the specifed file. +static void writeJSON(StringRef OrigDIVerifyBugsReportFilePath, + StringRef FileNameFromCU, StringRef NameOfWrappedPass, + llvm::json::Array &Bugs) { + std::error_code EC; + raw_fd_ostream OS_FILE{OrigDIVerifyBugsReportFilePath, EC, + sys::fs::OF_Append | sys::fs::OF_Text}; + if (EC) { + errs() << "Could not open file: " << EC.message() << ", " + << OrigDIVerifyBugsReportFilePath << '\n'; + return; + } + + OS_FILE << "{\"file\":\"" << FileNameFromCU << "\", "; + + StringRef PassName = NameOfWrappedPass != "" ? NameOfWrappedPass : "no-name"; + OS_FILE << "\"pass\":\"" << PassName << "\", "; + + llvm::json::Value BugsToPrint{std::move(Bugs)}; + OS_FILE << "\"bugs\": " << BugsToPrint; + + OS_FILE << "}\n"; +} + bool llvm::checkDebugInfoMetadata(Module &M, iterator_range<Module::iterator> Functions, DebugInfoPerPassMap &DIPreservationMap, - StringRef Banner, - StringRef NameOfWrappedPass) { + StringRef Banner, StringRef NameOfWrappedPass, + StringRef OrigDIVerifyBugsReportFilePath) { LLVM_DEBUG(dbgs() << Banner << ": (after) " << NameOfWrappedPass << '\n'); if (!M.getNamedMetadata("llvm.dbg.cu")) { @@ -428,7 +481,8 @@ bool llvm::checkDebugInfoMetadata(Module &M, // TODO: Collect metadata other than DISubprograms. // Collect the DISubprogram. auto *SP = F.getSubprogram(); - DIPreservationAfter[NameOfWrappedPass].DIFunctions.insert({F.getName(), SP}); + DIPreservationAfter[NameOfWrappedPass].DIFunctions.insert( + {F.getName(), SP}); if (SP) LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n'); @@ -467,14 +521,22 @@ bool llvm::checkDebugInfoMetadata(Module &M, auto InstToDelete = DIPreservationAfter[NameOfWrappedPass].InstToDelete; - bool ResultForFunc = checkFunctions(DIFunctionsBefore, DIFunctionsAfter, - NameOfWrappedPass, FileNameFromCU); - bool ResultForInsts = - checkInstructions(DILocsBefore, DILocsAfter, InstToDelete, - NameOfWrappedPass, FileNameFromCU); + bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty(); + llvm::json::Array Bugs; + + bool ResultForFunc = + checkFunctions(DIFunctionsBefore, DIFunctionsAfter, NameOfWrappedPass, + FileNameFromCU, ShouldWriteIntoJSON, Bugs); + bool ResultForInsts = checkInstructions( + DILocsBefore, DILocsAfter, InstToDelete, NameOfWrappedPass, + FileNameFromCU, ShouldWriteIntoJSON, Bugs); bool Result = ResultForFunc && ResultForInsts; StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner; + if (ShouldWriteIntoJSON && !Bugs.empty()) + writeJSON(OrigDIVerifyBugsReportFilePath, FileNameFromCU, NameOfWrappedPass, + Bugs); + if (Result) dbg() << ResultBanner << ": PASS\n"; else @@ -680,15 +742,18 @@ struct CheckDebugifyModulePass : public ModulePass { "CheckModuleDebugify", Strip, StatsMap); return checkDebugInfoMetadata( M, M.functions(), *DIPreservationMap, - "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass); + "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass, + OrigDIVerifyBugsReportFilePath); } CheckDebugifyModulePass( bool Strip = false, StringRef NameOfWrappedPass = "", DebugifyStatsMap *StatsMap = nullptr, enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, - DebugInfoPerPassMap *DIPreservationMap = nullptr) + DebugInfoPerPassMap *DIPreservationMap = nullptr, + StringRef OrigDIVerifyBugsReportFilePath = "") : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass), + OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath), StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode), Strip(Strip) {} @@ -700,6 +765,7 @@ struct CheckDebugifyModulePass : public ModulePass { private: StringRef NameOfWrappedPass; + StringRef OrigDIVerifyBugsReportFilePath; DebugifyStatsMap *StatsMap; DebugInfoPerPassMap *DIPreservationMap; enum DebugifyMode Mode; @@ -718,15 +784,18 @@ struct CheckDebugifyFunctionPass : public FunctionPass { Strip, StatsMap); return checkDebugInfoMetadata( M, make_range(FuncIt, std::next(FuncIt)), *DIPreservationMap, - "CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass); + "CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass, + OrigDIVerifyBugsReportFilePath); } CheckDebugifyFunctionPass( bool Strip = false, StringRef NameOfWrappedPass = "", DebugifyStatsMap *StatsMap = nullptr, enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, - DebugInfoPerPassMap *DIPreservationMap = nullptr) + DebugInfoPerPassMap *DIPreservationMap = nullptr, + StringRef OrigDIVerifyBugsReportFilePath = "") : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass), + OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath), StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode), Strip(Strip) {} @@ -738,6 +807,7 @@ struct CheckDebugifyFunctionPass : public FunctionPass { private: StringRef NameOfWrappedPass; + StringRef OrigDIVerifyBugsReportFilePath; DebugifyStatsMap *StatsMap; DebugInfoPerPassMap *DIPreservationMap; enum DebugifyMode Mode; @@ -794,22 +864,26 @@ PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { ModulePass *createCheckDebugifyModulePass( bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, - enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap) { + enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap, + StringRef OrigDIVerifyBugsReportFilePath) { if (Mode == DebugifyMode::SyntheticDebugInfo) return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap); assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); return new CheckDebugifyModulePass(false, NameOfWrappedPass, nullptr, Mode, - DIPreservationMap); + DIPreservationMap, + OrigDIVerifyBugsReportFilePath); } FunctionPass *createCheckDebugifyFunctionPass( bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, - enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap) { + enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap, + StringRef OrigDIVerifyBugsReportFilePath) { if (Mode == DebugifyMode::SyntheticDebugInfo) return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap); assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); return new CheckDebugifyFunctionPass(false, NameOfWrappedPass, nullptr, Mode, - DIPreservationMap); + DIPreservationMap, + OrigDIVerifyBugsReportFilePath); } PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M, |