mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 02:16:05 +00:00
Gsymutil aggregation similar to DwarfDump --verify (#81154)
GsymUtil, like DwarfDump --verify, spews a *lot* of data necessary to understand/diagnose issues with DWARF data. The trouble is that the kind of information necessary to make the messages useful also makes them nearly impossible to easily categorize. I put together a similar output categorizer (https://github.com/llvm/llvm-project/pull/79648) that will emit a summary of issues identified at the bottom of the (very verbose) output, enabling easier tracking of issues as they arise or are addressed. There's a single output change, where a message "warning: Unable to retrieve DWO .debug_info section for some object files. (Remove the --quiet flag for full output)" was being dumped the first time it was encountered (in what looks like an attempt to make something easily grep-able), but rather than keep the output in the same order, that message is now a 'category' so gets emitted at the end of the output. The test 'tools/llvm-gsymutil/X86/elf-dwo.yaml' was changed to reflect this difference. --------- Co-authored-by: Kevin Frei <freik@meta.com>
This commit is contained in:
parent
a38152e215
commit
3bdc4c702d
@ -22,6 +22,7 @@ namespace gsym {
|
||||
struct CUInfo;
|
||||
struct FunctionInfo;
|
||||
class GsymCreator;
|
||||
class OutputAggregator;
|
||||
|
||||
/// A class that transforms the DWARF in a DWARFContext into GSYM information
|
||||
/// by populating the GsymCreator object that it is constructed with. This
|
||||
@ -52,9 +53,9 @@ public:
|
||||
///
|
||||
/// \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, raw_ostream *OS);
|
||||
llvm::Error convert(uint32_t NumThreads, OutputAggregator &OS);
|
||||
|
||||
llvm::Error verify(StringRef GsymPath, raw_ostream &OS);
|
||||
llvm::Error verify(StringRef GsymPath, OutputAggregator &OS);
|
||||
|
||||
private:
|
||||
|
||||
@ -79,7 +80,7 @@ private:
|
||||
/// information.
|
||||
///
|
||||
/// \param Die The DWARF debug info entry to parse.
|
||||
void handleDie(raw_ostream *Strm, CUInfo &CUI, DWARFDie Die);
|
||||
void handleDie(OutputAggregator &Strm, CUInfo &CUI, DWARFDie Die);
|
||||
|
||||
DWARFContext &DICtx;
|
||||
GsymCreator &Gsym;
|
||||
|
@ -28,6 +28,7 @@ namespace llvm {
|
||||
|
||||
namespace gsym {
|
||||
class FileWriter;
|
||||
class OutputAggregator;
|
||||
|
||||
/// GsymCreator is used to emit GSYM data to a stand alone file or section
|
||||
/// within a file.
|
||||
@ -360,7 +361,7 @@ public:
|
||||
/// function infos, and function infos that were merged or removed.
|
||||
/// \returns An error object that indicates success or failure of the
|
||||
/// finalize.
|
||||
llvm::Error finalize(llvm::raw_ostream &OS);
|
||||
llvm::Error finalize(OutputAggregator &OS);
|
||||
|
||||
/// Set the UUID value.
|
||||
///
|
||||
|
@ -13,8 +13,6 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
namespace object {
|
||||
class ObjectFile;
|
||||
}
|
||||
@ -22,6 +20,7 @@ class ObjectFile;
|
||||
namespace gsym {
|
||||
|
||||
class GsymCreator;
|
||||
class OutputAggregator;
|
||||
|
||||
class ObjectFileTransformer {
|
||||
public:
|
||||
@ -40,8 +39,8 @@ public:
|
||||
///
|
||||
/// \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,
|
||||
GsymCreator &Gsym);
|
||||
static llvm::Error convert(const object::ObjectFile &Obj,
|
||||
OutputAggregator &Output, GsymCreator &Gsym);
|
||||
};
|
||||
|
||||
} // namespace gsym
|
||||
|
75
llvm/include/llvm/DebugInfo/GSYM/OutputAggregator.h
Normal file
75
llvm/include/llvm/DebugInfo/GSYM/OutputAggregator.h
Normal file
@ -0,0 +1,75 @@
|
||||
//===- DwarfTransformer.h ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_GSYM_OUTPUTAGGREGATOR_H
|
||||
#define LLVM_DEBUGINFO_GSYM_OUTPUTAGGREGATOR_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/GSYM/ExtractRanges.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class raw_ostream;
|
||||
|
||||
namespace gsym {
|
||||
|
||||
class OutputAggregator {
|
||||
protected:
|
||||
// A std::map is preferable over an llvm::StringMap for presenting results
|
||||
// in a predictable order.
|
||||
std::map<std::string, unsigned> Aggregation;
|
||||
raw_ostream *Out;
|
||||
|
||||
public:
|
||||
OutputAggregator(raw_ostream *out) : Out(out) {}
|
||||
|
||||
size_t GetNumCategories() const { return Aggregation.size(); }
|
||||
|
||||
void Report(StringRef s, std::function<void(raw_ostream &o)> detailCallback) {
|
||||
Aggregation[std::string(s)]++;
|
||||
if (GetOS())
|
||||
detailCallback(*Out);
|
||||
}
|
||||
|
||||
void EnumerateResults(
|
||||
std::function<void(StringRef, unsigned)> handleCounts) const {
|
||||
for (auto &&[name, count] : Aggregation)
|
||||
handleCounts(name, count);
|
||||
}
|
||||
|
||||
raw_ostream *GetOS() const { return Out; }
|
||||
|
||||
// You can just use the stream, and if it's null, nothing happens.
|
||||
// Don't do a lot of stuff like this, but it's convenient for silly stuff.
|
||||
// It doesn't work with things that have custom insertion operators, though.
|
||||
template <typename T> OutputAggregator &operator<<(T &&value) {
|
||||
if (Out != nullptr)
|
||||
*Out << value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// For multi-threaded usage, we can collect stuff in another aggregator,
|
||||
// then merge it in here
|
||||
void Merge(const OutputAggregator &other) {
|
||||
for (auto &&[name, count] : other.Aggregation) {
|
||||
auto it = Aggregation.find(name);
|
||||
if (it == Aggregation.end())
|
||||
Aggregation.emplace(name, count);
|
||||
else
|
||||
it->second += count;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gsym
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_GSYM_OUTPUTAGGREGATOR_H
|
@ -21,6 +21,8 @@
|
||||
#include "llvm/DebugInfo/GSYM/GsymCreator.h"
|
||||
#include "llvm/DebugInfo/GSYM/GsymReader.h"
|
||||
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
|
||||
#include "llvm/DebugInfo/GSYM/OutputAggregator.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
using namespace llvm;
|
||||
@ -215,9 +217,9 @@ ConvertDWARFRanges(const DWARFAddressRangesVector &DwarfRanges) {
|
||||
return Ranges;
|
||||
}
|
||||
|
||||
static void parseInlineInfo(GsymCreator &Gsym, raw_ostream *Log, CUInfo &CUI,
|
||||
DWARFDie Die, uint32_t Depth, FunctionInfo &FI,
|
||||
InlineInfo &Parent,
|
||||
static void parseInlineInfo(GsymCreator &Gsym, OutputAggregator &Out,
|
||||
CUInfo &CUI, DWARFDie Die, uint32_t Depth,
|
||||
FunctionInfo &FI, InlineInfo &Parent,
|
||||
const AddressRanges &AllParentRanges,
|
||||
bool &WarnIfEmpty) {
|
||||
if (!hasInlineInfo(Die, Depth))
|
||||
@ -250,14 +252,18 @@ static void parseInlineInfo(GsymCreator &Gsym, raw_ostream *Log, CUInfo &CUI,
|
||||
// parsing for.
|
||||
if (AllParentRanges.contains(InlineRange)) {
|
||||
WarnIfEmpty = false;
|
||||
} else if (Log) {
|
||||
*Log << "error: inlined function DIE at "
|
||||
<< HEX32(Die.getOffset()) << " has a range ["
|
||||
<< HEX64(InlineRange.start()) << " - "
|
||||
<< HEX64(InlineRange.end()) << ") that isn't contained in "
|
||||
<< "any parent address ranges, this inline range will be "
|
||||
"removed.\n";
|
||||
}
|
||||
} else
|
||||
Out.Report("Function DIE has uncontained address range",
|
||||
[&](raw_ostream &OS) {
|
||||
OS << "error: inlined function DIE at "
|
||||
<< HEX32(Die.getOffset()) << " has a range ["
|
||||
<< HEX64(InlineRange.start()) << " - "
|
||||
<< HEX64(InlineRange.end())
|
||||
<< ") that isn't contained in "
|
||||
<< "any parent address ranges, this inline range "
|
||||
"will be "
|
||||
"removed.\n";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -281,26 +287,30 @@ static void parseInlineInfo(GsymCreator &Gsym, raw_ostream *Log, CUInfo &CUI,
|
||||
II.CallLine = dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_line), 0);
|
||||
// parse all children and append to parent
|
||||
for (DWARFDie ChildDie : Die.children())
|
||||
parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, II,
|
||||
parseInlineInfo(Gsym, Out, CUI, ChildDie, Depth + 1, FI, II,
|
||||
AllInlineRanges, WarnIfEmpty);
|
||||
Parent.Children.emplace_back(std::move(II));
|
||||
} else if (Log) {
|
||||
*Log << "error: inlined function DIE at " << HEX32(Die.getOffset())
|
||||
<< " has an invalid file index " << DwarfFileIdx
|
||||
<< " in its DW_AT_call_file attribute, this inline entry and all "
|
||||
<< "children will be removed.\n";
|
||||
}
|
||||
} else
|
||||
Out.Report(
|
||||
"Inlined function die has invlaid file index in DW_AT_call_file",
|
||||
[&](raw_ostream &OS) {
|
||||
OS << "error: inlined function DIE at " << HEX32(Die.getOffset())
|
||||
<< " has an invalid file index " << DwarfFileIdx
|
||||
<< " in its DW_AT_call_file attribute, this inline entry and "
|
||||
"all "
|
||||
<< "children will be removed.\n";
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (Tag == dwarf::DW_TAG_subprogram || Tag == dwarf::DW_TAG_lexical_block) {
|
||||
// skip this Die and just recurse down
|
||||
for (DWARFDie ChildDie : Die.children())
|
||||
parseInlineInfo(Gsym, Log, CUI, ChildDie, Depth + 1, FI, Parent,
|
||||
parseInlineInfo(Gsym, Out, CUI, ChildDie, Depth + 1, FI, Parent,
|
||||
AllParentRanges, WarnIfEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI,
|
||||
static void convertFunctionLineTable(OutputAggregator &Out, CUInfo &CUI,
|
||||
DWARFDie Die, GsymCreator &Gsym,
|
||||
FunctionInfo &FI) {
|
||||
std::vector<uint32_t> RowVector;
|
||||
@ -319,15 +329,15 @@ static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI,
|
||||
if (FilePath.empty()) {
|
||||
// If we had a DW_AT_decl_file, but got no file then we need to emit a
|
||||
// warning.
|
||||
if (Log) {
|
||||
Out.Report("Invalid file index in DW_AT_decl_file", [&](raw_ostream &OS) {
|
||||
const uint64_t DwarfFileIdx = dwarf::toUnsigned(
|
||||
Die.findRecursively(dwarf::DW_AT_decl_file), UINT32_MAX);
|
||||
*Log << "error: function DIE at " << HEX32(Die.getOffset())
|
||||
<< " has an invalid file index " << DwarfFileIdx
|
||||
<< " in its DW_AT_decl_file attribute, unable to create a single "
|
||||
<< "line entry from the DW_AT_decl_file/DW_AT_decl_line "
|
||||
<< "attributes.\n";
|
||||
}
|
||||
OS << "error: function DIE at " << HEX32(Die.getOffset())
|
||||
<< " has an invalid file index " << DwarfFileIdx
|
||||
<< " in its DW_AT_decl_file attribute, unable to create a single "
|
||||
<< "line entry from the DW_AT_decl_file/DW_AT_decl_line "
|
||||
<< "attributes.\n";
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (auto Line =
|
||||
@ -347,14 +357,15 @@ static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI,
|
||||
std::optional<uint32_t> OptFileIdx =
|
||||
CUI.DWARFToGSYMFileIndex(Gsym, Row.File);
|
||||
if (!OptFileIdx) {
|
||||
if (Log) {
|
||||
*Log << "error: function DIE at " << HEX32(Die.getOffset()) << " has "
|
||||
<< "a line entry with invalid DWARF file index, this entry will "
|
||||
<< "be removed:\n";
|
||||
Row.dumpTableHeader(*Log, /*Indent=*/0);
|
||||
Row.dump(*Log);
|
||||
*Log << "\n";
|
||||
}
|
||||
Out.Report(
|
||||
"Invalid file index in DWARF line table", [&](raw_ostream &OS) {
|
||||
OS << "error: function DIE at " << HEX32(Die.getOffset()) << " has "
|
||||
<< "a line entry with invalid DWARF file index, this entry will "
|
||||
<< "be removed:\n";
|
||||
Row.dumpTableHeader(OS, /*Indent=*/0);
|
||||
Row.dump(OS);
|
||||
OS << "\n";
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const uint32_t FileIdx = OptFileIdx.value();
|
||||
@ -367,12 +378,15 @@ static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI,
|
||||
// an error, but not worth stopping the creation of the GSYM.
|
||||
if (!FI.Range.contains(RowAddress)) {
|
||||
if (RowAddress < FI.Range.start()) {
|
||||
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());
|
||||
}
|
||||
Out.Report("Start address lies between valid Row table entries",
|
||||
[&](raw_ostream &OS) {
|
||||
OS << "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(OS, 0, DIDumpOptions::getForSingleDIE());
|
||||
});
|
||||
RowAddress = FI.Range.start();
|
||||
} else {
|
||||
continue;
|
||||
@ -388,20 +402,21 @@ static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI,
|
||||
// line entry we already have in our "function_info.Lines". If
|
||||
// so break out after printing a warning.
|
||||
auto FirstLE = FI.OptLineTable->first();
|
||||
if (FirstLE && *FirstLE == LE) {
|
||||
if (Log && !Gsym.isQuiet()) {
|
||||
*Log << "warning: duplicate line table detected for DIE:\n";
|
||||
Die.dump(*Log, 0, DIDumpOptions::getForSingleDIE());
|
||||
}
|
||||
} else {
|
||||
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());
|
||||
}
|
||||
}
|
||||
if (FirstLE && *FirstLE == LE)
|
||||
// if (Log && !Gsym.isQuiet()) { TODO <-- This looks weird
|
||||
Out.Report("Duplicate line table detected", [&](raw_ostream &OS) {
|
||||
OS << "warning: duplicate line table detected for DIE:\n";
|
||||
Die.dump(OS, 0, DIDumpOptions::getForSingleDIE());
|
||||
});
|
||||
else
|
||||
Out.Report("Non-monotonically increasing addresses",
|
||||
[&](raw_ostream &OS) {
|
||||
OS << "error: line table has addresses that do not "
|
||||
<< "monotonically increase:\n";
|
||||
for (uint32_t RowIndex2 : RowVector)
|
||||
CUI.LineTable->Rows[RowIndex2].dump(OS);
|
||||
Die.dump(OS, 0, DIDumpOptions::getForSingleDIE());
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@ -429,7 +444,8 @@ static void convertFunctionLineTable(raw_ostream *Log, CUInfo &CUI,
|
||||
FI.OptLineTable = std::nullopt;
|
||||
}
|
||||
|
||||
void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
|
||||
void DwarfTransformer::handleDie(OutputAggregator &Out, CUInfo &CUI,
|
||||
DWARFDie Die) {
|
||||
switch (Die.getTag()) {
|
||||
case dwarf::DW_TAG_subprogram: {
|
||||
Expected<DWARFAddressRangesVector> RangesOrError = Die.getAddressRanges();
|
||||
@ -442,11 +458,11 @@ void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
|
||||
break;
|
||||
auto NameIndex = getQualifiedNameIndex(Die, CUI.Language, Gsym);
|
||||
if (!NameIndex) {
|
||||
if (OS) {
|
||||
*OS << "error: function at " << HEX64(Die.getOffset())
|
||||
<< " has no name\n ";
|
||||
Die.dump(*OS, 0, DIDumpOptions::getForSingleDIE());
|
||||
}
|
||||
Out.Report("Function has no name", [&](raw_ostream &OS) {
|
||||
OS << "error: function at " << HEX64(Die.getOffset())
|
||||
<< " has no name\n ";
|
||||
Die.dump(OS, 0, DIDumpOptions::getForSingleDIE());
|
||||
});
|
||||
break;
|
||||
}
|
||||
// All ranges for the subprogram DIE in case it has multiple. We need to
|
||||
@ -472,8 +488,8 @@ void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
|
||||
|
||||
// Many linkers can't remove DWARF and might set the LowPC to zero. Since
|
||||
// high PC can be an offset from the low PC in more recent DWARF versions
|
||||
// we need to watch for a zero'ed low pc which we do using
|
||||
// ValidTextRanges below.
|
||||
// we need to watch for a zero'ed low pc which we do using ValidTextRanges
|
||||
// below.
|
||||
if (!Gsym.IsValidTextAddress(Range.LowPC)) {
|
||||
// We expect zero and -1 to be invalid addresses in DWARF depending
|
||||
// on the linker of the DWARF. This indicates a function was stripped
|
||||
@ -482,13 +498,15 @@ void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
|
||||
if (Range.LowPC != 0) {
|
||||
if (!Gsym.isQuiet()) {
|
||||
// Unexpected invalid address, emit a warning
|
||||
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());
|
||||
}
|
||||
Out.Report("Address range starts outside executable section",
|
||||
[&](raw_ostream &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;
|
||||
@ -498,14 +516,14 @@ void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
|
||||
FI.Range = {Range.LowPC, Range.HighPC};
|
||||
FI.Name = *NameIndex;
|
||||
if (CUI.LineTable)
|
||||
convertFunctionLineTable(OS, CUI, Die, Gsym, FI);
|
||||
convertFunctionLineTable(Out, CUI, Die, Gsym, FI);
|
||||
|
||||
if (hasInlineInfo(Die, 0)) {
|
||||
FI.Inline = InlineInfo();
|
||||
FI.Inline->Name = *NameIndex;
|
||||
FI.Inline->Ranges.insert(FI.Range);
|
||||
bool WarnIfEmpty = true;
|
||||
parseInlineInfo(Gsym, OS, CUI, Die, 0, FI, *FI.Inline,
|
||||
parseInlineInfo(Gsym, Out, CUI, Die, 0, FI, *FI.Inline,
|
||||
AllSubprogramRanges, WarnIfEmpty);
|
||||
// Make sure we at least got some valid inline info other than just
|
||||
// the top level function. If we didn't then remove the inline info
|
||||
@ -517,11 +535,14 @@ void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
|
||||
// information object, we will know if we got anything valid from the
|
||||
// debug info.
|
||||
if (FI.Inline->Children.empty()) {
|
||||
if (WarnIfEmpty && 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());
|
||||
}
|
||||
if (WarnIfEmpty && !Gsym.isQuiet())
|
||||
Out.Report("DIE contains inline functions with no valid ranges",
|
||||
[&](raw_ostream &OS) {
|
||||
OS << "warning: DIE contains inline function "
|
||||
"information that has no valid ranges, removing "
|
||||
"inline information:\n";
|
||||
Die.dump(OS, 0, DIDumpOptions::getForSingleDIE());
|
||||
});
|
||||
FI.Inline = std::nullopt;
|
||||
}
|
||||
}
|
||||
@ -532,33 +553,28 @@ void DwarfTransformer::handleDie(raw_ostream *OS, CUInfo &CUI, DWARFDie Die) {
|
||||
break;
|
||||
}
|
||||
for (DWARFDie ChildDie : Die.children())
|
||||
handleDie(OS, CUI, ChildDie);
|
||||
handleDie(Out, CUI, ChildDie);
|
||||
}
|
||||
|
||||
Error DwarfTransformer::convert(uint32_t NumThreads, raw_ostream *OS) {
|
||||
Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
|
||||
size_t NumBefore = Gsym.getNumFunctionInfos();
|
||||
std::once_flag flag;
|
||||
auto getDie = [&](DWARFUnit &DwarfUnit) -> DWARFDie {
|
||||
DWARFDie ReturnDie = DwarfUnit.getUnitDIE(false);
|
||||
if (DwarfUnit.getDWOId()) {
|
||||
DWARFUnit *DWOCU = DwarfUnit.getNonSkeletonUnitDIE(false).getDwarfUnit();
|
||||
if (!DWOCU->isDWOUnit()) {
|
||||
if (OS) {
|
||||
std::string DWOName = dwarf::toString(
|
||||
DwarfUnit.getUnitDIE().find(
|
||||
{dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
|
||||
"");
|
||||
*OS << "warning: Unable to retrieve DWO .debug_info section for "
|
||||
<< DWOName << "\n";
|
||||
} else {
|
||||
std::call_once(flag, []() {
|
||||
outs()
|
||||
<< "warning: Unable to retrieve DWO .debug_info section for "
|
||||
"some "
|
||||
"object files. (Remove the --quiet flag for full output)\n";
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!DWOCU->isDWOUnit())
|
||||
Out.Report(
|
||||
"warning: Unable to retrieve DWO .debug_info section for some "
|
||||
"object files. (Remove the --quiet flag for full output)",
|
||||
[&](raw_ostream &OS) {
|
||||
std::string DWOName = dwarf::toString(
|
||||
DwarfUnit.getUnitDIE().find(
|
||||
{dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
|
||||
"");
|
||||
OS << "warning: Unable to retrieve DWO .debug_info section for "
|
||||
<< DWOName << "\n";
|
||||
});
|
||||
else {
|
||||
ReturnDie = DWOCU->getUnitDIE(false);
|
||||
}
|
||||
}
|
||||
@ -570,7 +586,7 @@ Error DwarfTransformer::convert(uint32_t NumThreads, raw_ostream *OS) {
|
||||
for (const auto &CU : DICtx.compile_units()) {
|
||||
DWARFDie Die = getDie(*CU);
|
||||
CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
|
||||
handleDie(OS, CUI, Die);
|
||||
handleDie(Out, CUI, Die);
|
||||
}
|
||||
} else {
|
||||
// LLVM Dwarf parser is not thread-safe and we need to parse all DWARF up
|
||||
@ -596,29 +612,31 @@ Error DwarfTransformer::convert(uint32_t NumThreads, raw_ostream *OS) {
|
||||
DWARFDie Die = getDie(*CU);
|
||||
if (Die) {
|
||||
CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
|
||||
pool.async([this, CUI, &LogMutex, OS, Die]() mutable {
|
||||
std::string ThreadLogStorage;
|
||||
raw_string_ostream ThreadOS(ThreadLogStorage);
|
||||
handleDie(OS ? &ThreadOS: nullptr, CUI, Die);
|
||||
ThreadOS.flush();
|
||||
if (OS && !ThreadLogStorage.empty()) {
|
||||
// Print ThreadLogStorage lines into an actual stream under a lock
|
||||
std::lock_guard<std::mutex> guard(LogMutex);
|
||||
*OS << ThreadLogStorage;
|
||||
pool.async([this, CUI, &LogMutex, Out, Die]() mutable {
|
||||
std::string storage;
|
||||
raw_string_ostream StrStream(storage);
|
||||
OutputAggregator ThreadOut(Out.GetOS() ? &StrStream : nullptr);
|
||||
handleDie(ThreadOut, CUI, Die);
|
||||
// Print ThreadLogStorage lines into an actual stream under a lock
|
||||
std::lock_guard<std::mutex> guard(LogMutex);
|
||||
if (Out.GetOS()) {
|
||||
StrStream.flush();
|
||||
Out << storage;
|
||||
}
|
||||
Out.Merge(ThreadOut);
|
||||
});
|
||||
}
|
||||
}
|
||||
pool.wait();
|
||||
}
|
||||
size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
|
||||
if (OS)
|
||||
*OS << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n";
|
||||
Out << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n";
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
llvm::Error DwarfTransformer::verify(StringRef GsymPath, raw_ostream &Log) {
|
||||
Log << "Verifying GSYM file \"" << GsymPath << "\":\n";
|
||||
llvm::Error DwarfTransformer::verify(StringRef GsymPath,
|
||||
OutputAggregator &Out) {
|
||||
Out << "Verifying GSYM file \"" << GsymPath << "\":\n";
|
||||
|
||||
auto Gsym = GsymReader::openFile(GsymPath);
|
||||
if (!Gsym)
|
||||
@ -637,9 +655,9 @@ llvm::Error DwarfTransformer::verify(StringRef GsymPath, raw_ostream &Log) {
|
||||
|
||||
auto FI = Gsym->getFunctionInfo(*FuncAddr);
|
||||
if (!FI)
|
||||
return createStringError(std::errc::invalid_argument,
|
||||
"failed to extract function info for address 0x%"
|
||||
PRIu64, *FuncAddr);
|
||||
return createStringError(
|
||||
std::errc::invalid_argument,
|
||||
"failed to extract function info for address 0x%" PRIu64, *FuncAddr);
|
||||
|
||||
for (auto Addr = *FuncAddr; Addr < *FuncAddr + FI->size(); ++Addr) {
|
||||
const object::SectionedAddress SectAddr{
|
||||
@ -664,24 +682,27 @@ llvm::Error DwarfTransformer::verify(StringRef GsymPath, raw_ostream &Log) {
|
||||
}
|
||||
if (NumDwarfInlineInfos > 0 &&
|
||||
NumDwarfInlineInfos != LR->Locations.size()) {
|
||||
Log << "error: address " << HEX64(Addr) << " has "
|
||||
<< NumDwarfInlineInfos << " DWARF inline frames and GSYM has "
|
||||
<< LR->Locations.size() << "\n";
|
||||
Log << " " << NumDwarfInlineInfos << " DWARF frames:\n";
|
||||
for (size_t Idx = 0; Idx < NumDwarfInlineInfos; ++Idx) {
|
||||
const auto &dii = DwarfInlineInfos.getFrame(Idx);
|
||||
Log << " [" << Idx << "]: " << dii.FunctionName << " @ "
|
||||
<< dii.FileName << ':' << dii.Line << '\n';
|
||||
if (Out.GetOS()) {
|
||||
raw_ostream &Log = *Out.GetOS();
|
||||
Log << "error: address " << HEX64(Addr) << " has "
|
||||
<< NumDwarfInlineInfos << " DWARF inline frames and GSYM has "
|
||||
<< LR->Locations.size() << "\n";
|
||||
Log << " " << NumDwarfInlineInfos << " DWARF frames:\n";
|
||||
for (size_t Idx = 0; Idx < NumDwarfInlineInfos; ++Idx) {
|
||||
const auto &dii = DwarfInlineInfos.getFrame(Idx);
|
||||
Log << " [" << Idx << "]: " << dii.FunctionName << " @ "
|
||||
<< dii.FileName << ':' << dii.Line << '\n';
|
||||
}
|
||||
Log << " " << LR->Locations.size() << " GSYM frames:\n";
|
||||
for (size_t Idx = 0, count = LR->Locations.size(); Idx < count;
|
||||
++Idx) {
|
||||
const auto &gii = LR->Locations[Idx];
|
||||
Log << " [" << Idx << "]: " << gii.Name << " @ " << gii.Dir
|
||||
<< '/' << gii.Base << ':' << gii.Line << '\n';
|
||||
}
|
||||
DwarfInlineInfos = DICtx.getInliningInfoForAddress(SectAddr, DLIS);
|
||||
Gsym->dump(Log, *FI);
|
||||
}
|
||||
Log << " " << LR->Locations.size() << " GSYM frames:\n";
|
||||
for (size_t Idx = 0, count = LR->Locations.size();
|
||||
Idx < count; ++Idx) {
|
||||
const auto &gii = LR->Locations[Idx];
|
||||
Log << " [" << Idx << "]: " << gii.Name << " @ " << gii.Dir
|
||||
<< '/' << gii.Base << ':' << gii.Line << '\n';
|
||||
}
|
||||
DwarfInlineInfos = DICtx.getInliningInfoForAddress(SectAddr, DLIS);
|
||||
Gsym->dump(Log, *FI);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -693,17 +714,18 @@ llvm::Error DwarfTransformer::verify(StringRef GsymPath, raw_ostream &Log) {
|
||||
gsymFilename = LR->getSourceFile(Idx);
|
||||
// Verify function name
|
||||
if (dii.FunctionName.find(gii.Name.str()) != 0)
|
||||
Log << "error: address " << HEX64(Addr) << " DWARF function \""
|
||||
Out << "error: address " << HEX64(Addr) << " DWARF function \""
|
||||
<< dii.FunctionName.c_str()
|
||||
<< "\" doesn't match GSYM function \"" << gii.Name << "\"\n";
|
||||
|
||||
// Verify source file path
|
||||
if (dii.FileName != gsymFilename)
|
||||
Log << "error: address " << HEX64(Addr) << " DWARF path \""
|
||||
Out << "error: address " << HEX64(Addr) << " DWARF path \""
|
||||
<< dii.FileName.c_str() << "\" doesn't match GSYM path \""
|
||||
<< gsymFilename.c_str() << "\"\n";
|
||||
// Verify source file line
|
||||
if (dii.Line != gii.Line)
|
||||
Log << "error: address " << HEX64(Addr) << " DWARF line "
|
||||
Out << "error: address " << HEX64(Addr) << " DWARF line "
|
||||
<< dii.Line << " != GSYM line " << gii.Line << "\n";
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "llvm/DebugInfo/GSYM/FileWriter.h"
|
||||
#include "llvm/DebugInfo/GSYM/Header.h"
|
||||
#include "llvm/DebugInfo/GSYM/LineTable.h"
|
||||
#include "llvm/DebugInfo/GSYM/OutputAggregator.h"
|
||||
#include "llvm/MC/StringTableBuilder.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
@ -188,7 +189,7 @@ llvm::Error GsymCreator::encode(FileWriter &O) const {
|
||||
return ErrorSuccess();
|
||||
}
|
||||
|
||||
llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
|
||||
llvm::Error GsymCreator::finalize(OutputAggregator &Out) {
|
||||
std::lock_guard<std::mutex> Guard(Mutex);
|
||||
if (Finalized)
|
||||
return createStringError(std::errc::invalid_argument, "already finalized");
|
||||
@ -247,26 +248,29 @@ llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
|
||||
// address ranges that have debug info are last in
|
||||
// the sort.
|
||||
if (!(Prev == Curr)) {
|
||||
if (Prev.hasRichInfo() && Curr.hasRichInfo()) {
|
||||
if (!Quiet) {
|
||||
OS << "warning: same address range contains "
|
||||
"different debug "
|
||||
<< "info. Removing:\n"
|
||||
<< Prev << "\nIn favor of this one:\n"
|
||||
<< Curr << "\n";
|
||||
}
|
||||
}
|
||||
if (Prev.hasRichInfo() && Curr.hasRichInfo())
|
||||
Out.Report(
|
||||
"Duplicate address ranges with different debug info.",
|
||||
[&](raw_ostream &OS) {
|
||||
OS << "warning: same address range contains "
|
||||
"different debug "
|
||||
<< "info. Removing:\n"
|
||||
<< Prev << "\nIn favor of this one:\n"
|
||||
<< Curr << "\n";
|
||||
});
|
||||
|
||||
// We want to swap the current entry with the previous since
|
||||
// later entries with the same range always have more debug info
|
||||
// or different debug info.
|
||||
std::swap(Prev, Curr);
|
||||
}
|
||||
} else {
|
||||
if (!Quiet) { // print warnings about overlaps
|
||||
Out.Report("Overlapping function ranges", [&](raw_ostream &OS) {
|
||||
// print warnings about overlaps
|
||||
OS << "warning: function ranges overlap:\n"
|
||||
<< Prev << "\n"
|
||||
<< Curr << "\n";
|
||||
}
|
||||
});
|
||||
FinalizedFuncs.emplace_back(std::move(Curr));
|
||||
}
|
||||
} else {
|
||||
@ -293,8 +297,8 @@ llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
|
||||
Funcs.back().Range = {Funcs.back().Range.start(), Range->end()};
|
||||
}
|
||||
}
|
||||
OS << "Pruned " << NumBefore - Funcs.size() << " functions, ended with "
|
||||
<< Funcs.size() << " total\n";
|
||||
Out << "Pruned " << NumBefore - Funcs.size() << " functions, ended with "
|
||||
<< Funcs.size() << " total\n";
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
@ -494,8 +498,9 @@ llvm::Error GsymCreator::saveSegments(StringRef Path,
|
||||
GsymCreator *GC = ExpectedGC->get();
|
||||
if (GC == NULL)
|
||||
break; // We had not more functions to encode.
|
||||
raw_null_ostream ErrorStrm;
|
||||
llvm::Error Err = GC->finalize(ErrorStrm);
|
||||
// Don't collect any messages at all
|
||||
OutputAggregator Out(nullptr);
|
||||
llvm::Error Err = GC->finalize(Out);
|
||||
if (Err)
|
||||
return Err;
|
||||
std::string SegmentedGsymPath;
|
||||
|
@ -14,8 +14,9 @@
|
||||
#include "llvm/Support/DataExtractor.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
|
||||
#include "llvm/DebugInfo/GSYM/GsymCreator.h"
|
||||
#include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
|
||||
#include "llvm/DebugInfo/GSYM/OutputAggregator.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace gsym;
|
||||
@ -68,7 +69,7 @@ static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {
|
||||
}
|
||||
|
||||
llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
|
||||
raw_ostream *Log,
|
||||
OutputAggregator &Out,
|
||||
GsymCreator &Gsym) {
|
||||
using namespace llvm::object;
|
||||
|
||||
@ -99,8 +100,8 @@ llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
|
||||
const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;
|
||||
Expected<StringRef> Name = Sym.getName();
|
||||
if (!Name) {
|
||||
if (Log)
|
||||
logAllUnhandledErrors(Name.takeError(), *Log,
|
||||
if (Out.GetOS())
|
||||
logAllUnhandledErrors(Name.takeError(), *Out.GetOS(),
|
||||
"ObjectFileTransformer: ");
|
||||
else
|
||||
consumeError(Name.takeError());
|
||||
@ -114,8 +115,8 @@ llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
|
||||
FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy)));
|
||||
}
|
||||
size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
|
||||
if (Log)
|
||||
*Log << "Loaded " << FunctionsAddedCount
|
||||
<< " functions from symbol table.\n";
|
||||
if (Out.GetOS())
|
||||
*Out.GetOS() << "Loaded " << FunctionsAddedCount
|
||||
<< " functions from symbol table.\n";
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -15,8 +15,8 @@
|
||||
|
||||
## WARNING-QUIET: Input file: {{.*\.yaml\.tmp}}
|
||||
## WARNING-QUIET: Output file (x86_64): {{.*\.yaml\.tmp\.gsym}}
|
||||
## WARNING-QUIET: warning: Unable to retrieve DWO .debug_info section for some object files. (Remove the --quiet flag for full output)
|
||||
## WARNING-QUIET: Pruned 0 functions, ended with 10 total
|
||||
## WARNING-QUIET: warning: Unable to retrieve DWO .debug_info section for some object files. (Remove the --quiet flag for full output)
|
||||
|
||||
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
|
||||
#include "llvm/DebugInfo/GSYM/LookupResult.h"
|
||||
#include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
|
||||
#include "llvm/DebugInfo/GSYM/OutputAggregator.h"
|
||||
#include <optional>
|
||||
|
||||
using namespace llvm;
|
||||
@ -300,16 +301,10 @@ static std::optional<uint64_t> getImageBaseAddress(object::ObjectFile &Obj) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static llvm::Error handleObjectFile(ObjectFile &Obj,
|
||||
const std::string &OutFile) {
|
||||
static llvm::Error handleObjectFile(ObjectFile &Obj, const std::string &OutFile,
|
||||
OutputAggregator &Out) {
|
||||
auto ThreadCount =
|
||||
NumThreads > 0 ? NumThreads : std::thread::hardware_concurrency();
|
||||
auto &OS = outs();
|
||||
// Make a stream refernce that will become a /dev/null log stream if
|
||||
// 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.
|
||||
raw_ostream *LogOS = Quiet ? nullptr : &outs();
|
||||
|
||||
GsymCreator Gsym(Quiet);
|
||||
|
||||
@ -354,17 +349,17 @@ static llvm::Error handleObjectFile(ObjectFile &Obj,
|
||||
Gsym.SetValidTextRanges(TextRanges);
|
||||
|
||||
// Convert all DWARF to GSYM.
|
||||
if (auto Err = DT.convert(ThreadCount, LogOS))
|
||||
if (auto Err = DT.convert(ThreadCount, Out))
|
||||
return Err;
|
||||
|
||||
// Get the UUID and convert symbol table to GSYM.
|
||||
if (auto Err = ObjectFileTransformer::convert(Obj, LogOS, Gsym))
|
||||
if (auto Err = ObjectFileTransformer::convert(Obj, Out, Gsym))
|
||||
return Err;
|
||||
|
||||
// Finalize the GSYM to make it ready to save to disk. This will remove
|
||||
// duplicate FunctionInfo entries where we might have found an entry from
|
||||
// debug info and also a symbol table entry from the object file.
|
||||
if (auto Err = Gsym.finalize(OS))
|
||||
if (auto Err = Gsym.finalize(Out))
|
||||
return Err;
|
||||
|
||||
// Save the GSYM file to disk.
|
||||
@ -381,7 +376,7 @@ static llvm::Error handleObjectFile(ObjectFile &Obj,
|
||||
// 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, OS))
|
||||
if (auto Err = DT.verify(OutFile, Out))
|
||||
return Err;
|
||||
}
|
||||
|
||||
@ -389,7 +384,8 @@ static llvm::Error handleObjectFile(ObjectFile &Obj,
|
||||
}
|
||||
|
||||
static llvm::Error handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
|
||||
const std::string &OutFile) {
|
||||
const std::string &OutFile,
|
||||
OutputAggregator &Out) {
|
||||
Expected<std::unique_ptr<Binary>> BinOrErr = object::createBinary(Buffer);
|
||||
error(Filename, errorToErrorCode(BinOrErr.takeError()));
|
||||
|
||||
@ -397,7 +393,7 @@ static llvm::Error handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
|
||||
Triple ObjTriple(Obj->makeTriple());
|
||||
auto ArchName = ObjTriple.getArchName();
|
||||
outs() << "Output file (" << ArchName << "): " << OutFile << "\n";
|
||||
if (auto Err = handleObjectFile(*Obj, OutFile))
|
||||
if (auto Err = handleObjectFile(*Obj, OutFile, Out))
|
||||
return Err;
|
||||
} else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get())) {
|
||||
// Iterate over all contained architectures and filter out any that were
|
||||
@ -431,7 +427,7 @@ static llvm::Error handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
|
||||
ArchOutFile.append(ArchName.str());
|
||||
}
|
||||
outs() << "Output file (" << ArchName << "): " << ArchOutFile << "\n";
|
||||
if (auto Err = handleObjectFile(*Obj, ArchOutFile))
|
||||
if (auto Err = handleObjectFile(*Obj, ArchOutFile, Out))
|
||||
return Err;
|
||||
}
|
||||
}
|
||||
@ -439,15 +435,16 @@ static llvm::Error handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
|
||||
}
|
||||
|
||||
static llvm::Error handleFileConversionToGSYM(StringRef Filename,
|
||||
const std::string &OutFile) {
|
||||
const std::string &OutFile,
|
||||
OutputAggregator &Out) {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(Filename);
|
||||
error(Filename, BuffOrErr.getError());
|
||||
std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
|
||||
return handleBuffer(Filename, *Buffer, OutFile);
|
||||
return handleBuffer(Filename, *Buffer, OutFile, Out);
|
||||
}
|
||||
|
||||
static llvm::Error convertFileToGSYM(raw_ostream &OS) {
|
||||
static llvm::Error convertFileToGSYM(OutputAggregator &Out) {
|
||||
// Expand any .dSYM bundles to the individual object files contained therein.
|
||||
std::vector<std::string> Objects;
|
||||
std::string OutFile = OutputFilename;
|
||||
@ -456,7 +453,7 @@ static llvm::Error convertFileToGSYM(raw_ostream &OS) {
|
||||
OutFile += ".gsym";
|
||||
}
|
||||
|
||||
OS << "Input file: " << ConvertFilename << "\n";
|
||||
Out << "Input file: " << ConvertFilename << "\n";
|
||||
|
||||
if (auto DsymObjectsOrErr =
|
||||
MachOObjectFile::findDsymObjectMembers(ConvertFilename)) {
|
||||
@ -469,7 +466,7 @@ static llvm::Error convertFileToGSYM(raw_ostream &OS) {
|
||||
}
|
||||
|
||||
for (StringRef Object : Objects)
|
||||
if (Error Err = handleFileConversionToGSYM(Object, OutFile))
|
||||
if (Error Err = handleFileConversionToGSYM(Object, OutFile, Out))
|
||||
return Err;
|
||||
return Error::success();
|
||||
}
|
||||
@ -507,6 +504,7 @@ int llvm_gsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
|
||||
|
||||
raw_ostream &OS = outs();
|
||||
|
||||
OutputAggregator Aggregation(&OS);
|
||||
if (!ConvertFilename.empty()) {
|
||||
// Convert DWARF to GSYM
|
||||
if (!InputFilenames.empty()) {
|
||||
@ -515,8 +513,12 @@ int llvm_gsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
|
||||
return 1;
|
||||
}
|
||||
// Call error() if we have an error and it will exit with a status of 1
|
||||
if (auto Err = convertFileToGSYM(OS))
|
||||
if (auto Err = convertFileToGSYM(Aggregation))
|
||||
error("DWARF conversion failed: ", std::move(Err));
|
||||
// Report the errors from aggregator:
|
||||
Aggregation.EnumerateResults([&](StringRef category, unsigned count) {
|
||||
OS << category << " occurred " << count << " time(s)\n";
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/DebugInfo/GSYM/GsymReader.h"
|
||||
#include "llvm/DebugInfo/GSYM/Header.h"
|
||||
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
|
||||
#include "llvm/DebugInfo/GSYM/OutputAggregator.h"
|
||||
#include "llvm/DebugInfo/GSYM/StringTable.h"
|
||||
#include "llvm/ObjectYAML/DWARFEmitter.h"
|
||||
#include "llvm/Support/DataExtractor.h"
|
||||
@ -971,9 +972,10 @@ TEST(GSYMTest, TestGsymCreatorEncodeErrors) {
|
||||
"GsymCreator wasn't finalized prior to encoding");
|
||||
std::string finalizeIssues;
|
||||
raw_string_ostream OS(finalizeIssues);
|
||||
llvm::Error finalizeErr = GC.finalize(OS);
|
||||
OutputAggregator Agg(&OS);
|
||||
llvm::Error finalizeErr = GC.finalize(Agg);
|
||||
ASSERT_FALSE(bool(finalizeErr));
|
||||
finalizeErr = GC.finalize(OS);
|
||||
finalizeErr = GC.finalize(Agg);
|
||||
ASSERT_TRUE(bool(finalizeErr));
|
||||
checkError("already finalized", std::move(finalizeErr));
|
||||
// Verify we get an error trying to encode a GsymCreator with a UUID that is
|
||||
@ -1043,7 +1045,8 @@ TEST(GSYMTest, TestGsymCreator1ByteAddrOffsets) {
|
||||
const uint32_t Func2Name = GC.insertString("bar");
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr+0x00, 0x10, Func1Name));
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20, 0x10, Func2Name));
|
||||
Error Err = GC.finalize(llvm::nulls());
|
||||
OutputAggregator Null(nullptr);
|
||||
Error Err = GC.finalize(Null);
|
||||
ASSERT_FALSE(Err);
|
||||
TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize,
|
||||
BaseAddr,
|
||||
@ -1065,7 +1068,8 @@ TEST(GSYMTest, TestGsymCreator2ByteAddrOffsets) {
|
||||
const uint32_t Func2Name = GC.insertString("bar");
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr+0x200, 0x100, Func2Name));
|
||||
Error Err = GC.finalize(llvm::nulls());
|
||||
OutputAggregator Null(nullptr);
|
||||
Error Err = GC.finalize(Null);
|
||||
ASSERT_FALSE(Err);
|
||||
TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize,
|
||||
BaseAddr,
|
||||
@ -1087,7 +1091,8 @@ TEST(GSYMTest, TestGsymCreator4ByteAddrOffsets) {
|
||||
const uint32_t Func2Name = GC.insertString("bar");
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr+0x20000, 0x100, Func2Name));
|
||||
Error Err = GC.finalize(llvm::nulls());
|
||||
OutputAggregator Null(nullptr);
|
||||
Error Err = GC.finalize(Null);
|
||||
ASSERT_FALSE(Err);
|
||||
TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize,
|
||||
BaseAddr,
|
||||
@ -1109,7 +1114,8 @@ TEST(GSYMTest, TestGsymCreator8ByteAddrOffsets) {
|
||||
const uint32_t Func2Name = GC.insertString("bar");
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr+0x000, 0x100, Func1Name));
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr+0x100000000, 0x100, Func2Name));
|
||||
Error Err = GC.finalize(llvm::nulls());
|
||||
OutputAggregator Null(nullptr);
|
||||
Error Err = GC.finalize(Null);
|
||||
ASSERT_FALSE(Err);
|
||||
TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize,
|
||||
BaseAddr,
|
||||
@ -1148,7 +1154,8 @@ TEST(GSYMTest, TestGsymReader) {
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
GC.addFunctionInfo(FunctionInfo(Func1Addr, FuncSize, Func1Name));
|
||||
GC.addFunctionInfo(FunctionInfo(Func2Addr, FuncSize, Func2Name));
|
||||
Error FinalizeErr = GC.finalize(llvm::nulls());
|
||||
OutputAggregator Null(nullptr);
|
||||
Error FinalizeErr = GC.finalize(Null);
|
||||
ASSERT_FALSE(FinalizeErr);
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
@ -1213,7 +1220,8 @@ TEST(GSYMTest, TestGsymLookups) {
|
||||
Inline3.Ranges.insert(AddressRange(0x1016, 0x1018));
|
||||
FI.Inline->Children.emplace_back(Inline3);
|
||||
GC.addFunctionInfo(std::move(FI));
|
||||
Error FinalizeErr = GC.finalize(llvm::nulls());
|
||||
OutputAggregator Null(nullptr);
|
||||
Error FinalizeErr = GC.finalize(Null);
|
||||
ASSERT_FALSE(FinalizeErr);
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
@ -1329,11 +1337,12 @@ TEST(GSYMTest, TestDWARFFunctionWithAddresses) {
|
||||
DWARFContext::create(*ErrOrSections, 8);
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
auto &OS = llvm::nulls();
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -1406,11 +1415,12 @@ TEST(GSYMTest, TestDWARFFunctionWithAddressAndOffset) {
|
||||
DWARFContext::create(*ErrOrSections, 8);
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
auto &OS = llvm::nulls();
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -1513,11 +1523,12 @@ TEST(GSYMTest, TestDWARFStructMethodNoMangled) {
|
||||
DWARFContext::create(*ErrOrSections, 8);
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
auto &OS = llvm::nulls();
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -1613,6 +1624,7 @@ TEST(GSYMTest, TestDWARFTextRanges) {
|
||||
DWARFContext::create(*ErrOrSections, 8);
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
auto &OS = llvm::nulls();
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
// Only allow addresses between [0x1000 - 0x2000) to be linked into the
|
||||
@ -1621,8 +1633,8 @@ TEST(GSYMTest, TestDWARFTextRanges) {
|
||||
TextRanges.insert(AddressRange(0x1000, 0x2000));
|
||||
GC.SetValidTextRanges(TextRanges);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -1650,8 +1662,8 @@ TEST(GSYMTest, TestEmptySymbolEndAddressOfTextRanges) {
|
||||
TextRanges.insert(AddressRange(0x1000, 0x2000));
|
||||
GC.SetValidTextRanges(TextRanges);
|
||||
GC.addFunctionInfo(FunctionInfo(0x1500, 0, GC.insertString("symbol")));
|
||||
auto &OS = llvm::nulls();
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
OutputAggregator Null(nullptr);
|
||||
ASSERT_THAT_ERROR(GC.finalize(Null), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -1816,11 +1828,12 @@ TEST(GSYMTest, TestDWARFInlineInfo) {
|
||||
DWARFContext::create(*ErrOrSections, 8);
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
auto &OS = llvm::nulls();
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -2076,11 +2089,12 @@ TEST(GSYMTest, TestDWARFNoLines) {
|
||||
DWARFContext::create(*ErrOrSections, 8);
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
auto &OS = llvm::nulls();
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -2255,11 +2269,12 @@ TEST(GSYMTest, TestDWARFDeadStripAddr4) {
|
||||
DWARFContext::create(*ErrOrSections, 4);
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
auto &OS = llvm::nulls();
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -2395,11 +2410,12 @@ TEST(GSYMTest, TestDWARFDeadStripAddr8) {
|
||||
DWARFContext::create(*ErrOrSections, 8);
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
auto &OS = llvm::nulls();
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -2430,7 +2446,8 @@ TEST(GSYMTest, TestGsymCreatorMultipleSymbolsWithNoSize) {
|
||||
const uint32_t Func2Name = GC.insertString("bar");
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr, 0, Func1Name));
|
||||
GC.addFunctionInfo(FunctionInfo(BaseAddr, 0, Func2Name));
|
||||
Error Err = GC.finalize(llvm::nulls());
|
||||
OutputAggregator Null(nullptr);
|
||||
Error Err = GC.finalize(Null);
|
||||
ASSERT_FALSE(Err);
|
||||
TestEncodeDecode(GC, llvm::endianness::little, GSYM_VERSION, AddrOffSize,
|
||||
BaseAddr,
|
||||
@ -2485,7 +2502,8 @@ static void AddFunctionInfo(GsymCreator &GC, const char *FuncName,
|
||||
// Finalize a GsymCreator, encode it and decode it and return the error or
|
||||
// GsymReader that was successfully decoded.
|
||||
static Expected<GsymReader> FinalizeEncodeAndDecode(GsymCreator &GC) {
|
||||
Error FinalizeErr = GC.finalize(llvm::nulls());
|
||||
OutputAggregator Null(nullptr);
|
||||
Error FinalizeErr = GC.finalize(Null);
|
||||
if (FinalizeErr)
|
||||
return std::move(FinalizeErr);
|
||||
SmallString<1024> Str;
|
||||
@ -3033,11 +3051,12 @@ TEST(GSYMTest, TestDWARFInlineRangeScopes) {
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
std::string errors;
|
||||
raw_string_ostream OS(errors);
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -3260,11 +3279,12 @@ TEST(GSYMTest, TestDWARFEmptyInline) {
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
std::string errors;
|
||||
raw_string_ostream OS(errors);
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -3496,11 +3516,12 @@ TEST(GSYMTest, TestFinalizeForLineTables) {
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
std::string errors;
|
||||
raw_string_ostream OS(errors);
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
const auto ByteOrder = llvm::endianness::native;
|
||||
@ -3775,11 +3796,12 @@ TEST(GSYMTest, TestRangeWarnings) {
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
std::string errors;
|
||||
raw_string_ostream OS(errors);
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
OS.flush();
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
@ -3977,11 +3999,12 @@ TEST(GSYMTest, TestEmptyRangeWarnings) {
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
std::string errors;
|
||||
raw_string_ostream OS(errors);
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
OS.flush();
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
@ -4129,11 +4152,12 @@ TEST(GSYMTest, TestEmptyLinkageName) {
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
std::string errors;
|
||||
raw_string_ostream OS(errors);
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
OS.flush();
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
@ -4290,11 +4314,12 @@ TEST(GSYMTest, TestLineTablesWithEmptyRanges) {
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
std::string errors;
|
||||
raw_string_ostream OS(errors);
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
OS.flush();
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
@ -4610,11 +4635,12 @@ TEST(GSYMTest, TestHandlingOfInvalidFileIndexes) {
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
std::string errors;
|
||||
raw_string_ostream OS(errors);
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
OS.flush();
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
@ -4825,11 +4851,12 @@ TEST(GSYMTest, TestLookupsOfOverlappingAndUnequalRanges) {
|
||||
ASSERT_TRUE(DwarfContext.get() != nullptr);
|
||||
std::string errors;
|
||||
raw_string_ostream OS(errors);
|
||||
OutputAggregator OSAgg(&OS);
|
||||
GsymCreator GC;
|
||||
DwarfTransformer DT(*DwarfContext, GC);
|
||||
const uint32_t ThreadCount = 1;
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, &OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OS), Succeeded());
|
||||
ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded());
|
||||
ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded());
|
||||
OS.flush();
|
||||
SmallString<512> Str;
|
||||
raw_svector_ostream OutStrm(Str);
|
||||
|
Loading…
x
Reference in New Issue
Block a user