diff --git a/llvm/include/llvm/DebugInfo/GSYM/DwarfTransformer.h b/llvm/include/llvm/DebugInfo/GSYM/DwarfTransformer.h --- a/llvm/include/llvm/DebugInfo/GSYM/DwarfTransformer.h +++ b/llvm/include/llvm/DebugInfo/GSYM/DwarfTransformer.h @@ -36,23 +36,25 @@ /// /// \param D The DWARF to use when converting to GSYM. /// - /// \param OS The stream to log warnings and non fatal issues to. - /// /// \param G The GSYM creator to populate with the function information /// from the debug info. - DwarfTransformer(DWARFContext &D, raw_ostream &OS, GsymCreator &G) : - DICtx(D), Log(OS), Gsym(G) {} + DwarfTransformer(DWARFContext &D, GsymCreator &G) : DICtx(D), Gsym(G) {} /// Extract the DWARF from the supplied object file and convert it into the /// Gsym format in the GsymCreator object that is passed in. Returns an /// error if something fatal is encountered. /// + /// \param NumThreads The number of threads that the conversion process can + /// use. + /// + /// \param OS The stream to log warnings and non fatal issues to. If NULL + /// then don't log. + /// /// \returns An error indicating any fatal issues that happen when parsing /// the DWARF, or Error::success() if all goes well. - llvm::Error convert(uint32_t NumThreads); - - llvm::Error verify(StringRef GsymPath); + llvm::Error convert(uint32_t NumThreads, raw_ostream *OS); + llvm::Error verify(StringRef GsymPath, raw_ostream &OS); private: @@ -69,17 +71,17 @@ /// \param Strm The thread specific log stream for any non fatal errors and /// warnings. Once a thread has finished parsing an entire compile unit, all /// information in this temporary stream will be forwarded to the member - /// variable log. This keeps logging thread safe. + /// variable log. This keeps logging thread safe. If the value is NULL, then + /// don't log. /// /// \param CUI The compile unit specific information that contains the DWARF /// line table, cached file list, and other compile unit specific /// information. /// /// \param Die The DWARF debug info entry to parse. - void handleDie(raw_ostream &Strm, CUInfo &CUI, DWARFDie Die); + void handleDie(raw_ostream *Strm, CUInfo &CUI, DWARFDie Die); DWARFContext &DICtx; - raw_ostream &Log; GsymCreator &Gsym; friend class DwarfTransformerTest; diff --git a/llvm/include/llvm/DebugInfo/GSYM/ObjectFileTransformer.h b/llvm/include/llvm/DebugInfo/GSYM/ObjectFileTransformer.h --- a/llvm/include/llvm/DebugInfo/GSYM/ObjectFileTransformer.h +++ b/llvm/include/llvm/DebugInfo/GSYM/ObjectFileTransformer.h @@ -32,15 +32,15 @@ /// /// \param Obj The object file that contains the DWARF debug info. /// - /// \param Log The stream to log warnings and non fatal issues to. + /// \param Log The stream to log warnings and non fatal issues to. If NULL, + /// don't log. /// /// \param Gsym The GSYM creator to populate with the function information /// from the debug info. /// /// \returns An error indicating any fatal issues that happen when parsing /// the DWARF, or Error::success() if all goes well. - static llvm::Error convert(const object::ObjectFile &Obj, - raw_ostream &Log, + static llvm::Error convert(const object::ObjectFile &Obj, raw_ostream *Log, GsymCreator &Gsym); }; diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp --- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp +++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp @@ -205,7 +205,7 @@ return false; } -static void parseInlineInfo(GsymCreator &Gsym, raw_ostream &Log, CUInfo &CUI, +static void parseInlineInfo(GsymCreator &Gsym, raw_ostream *Log, CUInfo &CUI, DWARFDie Die, uint32_t Depth, FunctionInfo &FI, InlineInfo &parent) { if (!hasInlineInfo(Die, Depth)) @@ -223,11 +223,11 @@ AddressRange InlineRange(Range.LowPC, Range.HighPC); if (parent.Ranges.contains(InlineRange)) { II.Ranges.insert(InlineRange); - } else { - Log << "error: inlined function DIE at " << HEX32(Die.getOffset()) - << " has a range [" << HEX64(Range.LowPC) << " - " - << HEX64(Range.HighPC) << ") that isn't contained in any parent " - << "address ranges, this inline range will be removed.\n"; + } else if (Log) { + *Log << "error: inlined function DIE at " << HEX32(Die.getOffset()) + << " has a range [" << HEX64(Range.LowPC) << " - " + << HEX64(Range.HighPC) << ") that isn't contained in any parent " + << "address ranges, this inline range will be removed.\n"; } } } @@ -252,7 +252,7 @@ } } -static void convertFunctionLineTable(raw_ostream &Log, CUInfo &CUI, +static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI, DWARFDie Die, GsymCreator &Gsym, FunctionInfo &FI) { std::vector RowVector; @@ -294,10 +294,12 @@ // an error, but not worth stopping the creation of the GSYM. if (!FI.Range.contains(RowAddress)) { if (RowAddress < FI.Range.start()) { - Log << "error: DIE has a start address whose LowPC is between the " - "line table Row[" << RowIndex << "] with address " - << HEX64(RowAddress) << " and the next one.\n"; - Die.dump(Log, 0, DIDumpOptions::getForSingleDIE()); + if (Log) { + *Log << "error: DIE has a start address whose LowPC is between the " + "line table Row[" << RowIndex << "] with address " + << HEX64(RowAddress) << " and the next one.\n"; + Die.dump(*Log, 0, DIDumpOptions::getForSingleDIE()); + } RowAddress = FI.Range.start(); } else { continue; @@ -314,18 +316,18 @@ // so break out after printing a warning. auto FirstLE = FI.OptLineTable->first(); if (FirstLE && *FirstLE == LE) { - if (!Gsym.isQuiet()) { - Log << "warning: duplicate line table detected for DIE:\n"; - Die.dump(Log, 0, DIDumpOptions::getForSingleDIE()); + if (Log && !Gsym.isQuiet()) { + *Log << "warning: duplicate line table detected for DIE:\n"; + Die.dump(*Log, 0, DIDumpOptions::getForSingleDIE()); } } else { - // Print out (ignore if os == nulls as this is expensive) - Log << "error: line table has addresses that do not " - << "monotonically increase:\n"; - for (uint32_t RowIndex2 : RowVector) { - CUI.LineTable->Rows[RowIndex2].dump(Log); + if (Log) { + *Log << "error: line table has addresses that do not " + << "monotonically increase:\n"; + for (uint32_t RowIndex2 : RowVector) + CUI.LineTable->Rows[RowIndex2].dump(*Log); + Die.dump(*Log, 0, DIDumpOptions::getForSingleDIE()); } - Die.dump(Log, 0, DIDumpOptions::getForSingleDIE()); } break; } @@ -354,7 +356,7 @@ FI.OptLineTable = std::nullopt; } -void DwarfTransformer::handleDie(raw_ostream &OS, CUInfo &CUI, DWARFDie Die) { +void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) { switch (Die.getTag()) { case dwarf::DW_TAG_subprogram: { Expected RangesOrError = Die.getAddressRanges(); @@ -367,9 +369,11 @@ break; auto NameIndex = getQualifiedNameIndex(Die, CUI.Language, Gsym); if (!NameIndex) { - OS << "error: function at " << HEX64(Die.getOffset()) - << " has no name\n "; - Die.dump(OS, 0, DIDumpOptions::getForSingleDIE()); + if (OS) { + *OS << "error: function at " << HEX64(Die.getOffset()) + << " has no name\n "; + Die.dump(*OS, 0, DIDumpOptions::getForSingleDIE()); + } break; } @@ -398,11 +402,13 @@ if (Range.LowPC != 0) { if (!Gsym.isQuiet()) { // Unexpected invalid address, emit a warning - OS << "warning: DIE has an address range whose start address is " - "not in any executable sections (" - << *Gsym.GetValidTextRanges() - << ") and will not be processed:\n"; - Die.dump(OS, 0, DIDumpOptions::getForSingleDIE()); + if (OS) { + *OS << "warning: DIE has an address range whose start address " + "is not in any executable sections (" + << *Gsym.GetValidTextRanges() + << ") and will not be processed:\n"; + Die.dump(*OS, 0, DIDumpOptions::getForSingleDIE()); + } } } break; @@ -429,10 +435,10 @@ // information object, we will know if we got anything valid from the // debug info. if (FI.Inline->Children.empty()) { - if (!Gsym.isQuiet()) { - OS << "warning: DIE contains inline function information that has " + if (OS && !Gsym.isQuiet()) { + *OS << "warning: DIE contains inline function information that has " "no valid ranges, removing inline information:\n"; - Die.dump(OS, 0, DIDumpOptions::getForSingleDIE()); + Die.dump(*OS, 0, DIDumpOptions::getForSingleDIE()); } FI.Inline = std::nullopt; } @@ -447,18 +453,18 @@ handleDie(OS, CUI, ChildDie); } -Error DwarfTransformer::convert(uint32_t NumThreads) { +Error DwarfTransformer::convert(uint32_t NumThreads, raw_ostream *OS) { size_t NumBefore = Gsym.getNumFunctionInfos(); auto getDie = [&](DWARFUnit &DwarfUnit) -> DWARFDie { DWARFDie ReturnDie = DwarfUnit.getUnitDIE(false); if (std::optional DWOId = DwarfUnit.getDWOId()) { DWARFUnit *DWOCU = DwarfUnit.getNonSkeletonUnitDIE(false).getDwarfUnit(); - if (!DWOCU->isDWOUnit()) { + if (OS && !DWOCU->isDWOUnit()) { std::string DWOName = dwarf::toString( DwarfUnit.getUnitDIE().find( {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), ""); - Log << "warning: Unable to retrieve DWO .debug_info section for " + *OS << "warning: Unable to retrieve DWO .debug_info section for " << DWOName << "\n"; } else { ReturnDie = DWOCU->getUnitDIE(false); @@ -472,7 +478,7 @@ for (const auto &CU : DICtx.compile_units()) { DWARFDie Die = getDie(*CU); CUInfo CUI(DICtx, dyn_cast(CU.get())); - handleDie(Log, CUI, Die); + handleDie(OS, CUI, Die); } } else { // LLVM Dwarf parser is not thread-safe and we need to parse all DWARF up @@ -498,15 +504,15 @@ DWARFDie Die = getDie(*CU); if (Die) { CUInfo CUI(DICtx, dyn_cast(CU.get())); - pool.async([this, CUI, &LogMutex, Die]() mutable { + pool.async([this, CUI, &LogMutex, OS, Die]() mutable { std::string ThreadLogStorage; raw_string_ostream ThreadOS(ThreadLogStorage); - handleDie(ThreadOS, CUI, Die); + handleDie(OS ? &ThreadOS: nullptr, CUI, Die); ThreadOS.flush(); - if (!ThreadLogStorage.empty()) { + if (OS && !ThreadLogStorage.empty()) { // Print ThreadLogStorage lines into an actual stream under a lock std::lock_guard guard(LogMutex); - Log << ThreadLogStorage; + *OS << ThreadLogStorage; } }); } @@ -514,11 +520,12 @@ pool.wait(); } size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore; - Log << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n"; + if (OS) + *OS << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n"; return Error::success(); } -llvm::Error DwarfTransformer::verify(StringRef GsymPath) { +llvm::Error DwarfTransformer::verify(StringRef GsymPath, raw_ostream &Log) { Log << "Verifying GSYM file \"" << GsymPath << "\":\n"; auto Gsym = GsymReader::openFile(GsymPath); diff --git a/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp b/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp --- a/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp +++ b/llvm/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp @@ -68,7 +68,7 @@ } llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj, - raw_ostream &Log, + raw_ostream *Log, GsymCreator &Gsym) { using namespace llvm::object; @@ -99,7 +99,11 @@ const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0; Expected Name = Sym.getName(); if (!Name) { - logAllUnhandledErrors(Name.takeError(), Log, "ObjectFileTransformer: "); + if (Log) + logAllUnhandledErrors(Name.takeError(), *Log, + "ObjectFileTransformer: "); + else + consumeError(Name.takeError()); continue; } // Remove the leading '_' character in any symbol names if there is one @@ -110,6 +114,8 @@ FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy))); } size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore; - Log << "Loaded " << FunctionsAddedCount << " functions from symbol table.\n"; + if (Log) + *Log << "Loaded " << FunctionsAddedCount + << " functions from symbol table.\n"; return Error::success(); } diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp --- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp +++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp @@ -311,7 +311,7 @@ // Quiet is true, or normal output if Quiet is false. This can stop the // errors and warnings from being displayed and producing too much output // when they aren't desired. - auto &LogOS = Quiet ? nulls() : outs(); + raw_ostream *LogOS = Quiet ? nullptr : &outs(); GsymCreator Gsym(Quiet); @@ -344,12 +344,12 @@ // Make a DWARF transformer object and populate the ranges of the code // so we don't end up adding invalid functions to GSYM data. - DwarfTransformer DT(*DICtx, LogOS, Gsym); + DwarfTransformer DT(*DICtx, Gsym); if (!TextRanges.empty()) Gsym.SetValidTextRanges(TextRanges); // Convert all DWARF to GSYM. - if (auto Err = DT.convert(ThreadCount)) + if (auto Err = DT.convert(ThreadCount, LogOS)) return Err; // Get the UUID and convert symbol table to GSYM. @@ -375,7 +375,7 @@ // Verify the DWARF if requested. This will ensure all the info in the DWARF // can be looked up in the GSYM and that all lookups get matching data. if (Verify) { - if (auto Err = DT.verify(OutFile)) + if (auto Err = DT.verify(OutFile, OS)) return Err; } diff --git a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp --- a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp +++ b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp @@ -1348,9 +1348,9 @@ ASSERT_TRUE(DwarfContext.get() != nullptr); auto &OS = llvm::nulls(); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -1425,9 +1425,9 @@ ASSERT_TRUE(DwarfContext.get() != nullptr); auto &OS = llvm::nulls(); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -1532,9 +1532,9 @@ ASSERT_TRUE(DwarfContext.get() != nullptr); auto &OS = llvm::nulls(); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -1632,14 +1632,14 @@ ASSERT_TRUE(DwarfContext.get() != nullptr); auto &OS = llvm::nulls(); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); // Only allow addresses between [0x1000 - 0x2000) to be linked into the // GSYM. AddressRanges TextRanges; TextRanges.insert(AddressRange(0x1000, 0x2000)); GC.SetValidTextRanges(TextRanges); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -1835,9 +1835,9 @@ ASSERT_TRUE(DwarfContext.get() != nullptr); auto &OS = llvm::nulls(); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -2095,9 +2095,9 @@ ASSERT_TRUE(DwarfContext.get() != nullptr); auto &OS = llvm::nulls(); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -2274,9 +2274,9 @@ ASSERT_TRUE(DwarfContext.get() != nullptr); auto &OS = llvm::nulls(); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -2414,9 +2414,9 @@ ASSERT_TRUE(DwarfContext.get() != nullptr); auto &OS = llvm::nulls(); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -3051,9 +3051,9 @@ std::string errors; raw_string_ostream OS(errors); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -3278,9 +3278,9 @@ std::string errors; raw_string_ostream OS(errors); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str); @@ -3514,9 +3514,9 @@ std::string errors; raw_string_ostream OS(errors); GsymCreator GC; - DwarfTransformer DT(*DwarfContext, OS, GC); + DwarfTransformer DT(*DwarfContext, GC); const uint32_t ThreadCount = 1; - ASSERT_THAT_ERROR(DT.convert(ThreadCount), Succeeded()); + ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded()); ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded()); SmallString<512> Str; raw_svector_ostream OutStrm(Str);