aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp220
1 files changed, 96 insertions, 124 deletions
diff --git a/contrib/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp b/contrib/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
index 60b6dbc6a12d..ee7b0efba5ea 100644
--- a/contrib/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
+++ b/contrib/llvm-project/llvm/lib/DebugInfo/GSYM/GsymCreator.cpp
@@ -61,9 +61,7 @@ uint32_t GsymCreator::copyFile(const GsymCreator &SrcGC, uint32_t FileIdx) {
return insertFileEntry(DstFE);
}
-
-llvm::Error GsymCreator::save(StringRef Path,
- llvm::support::endianness ByteOrder,
+llvm::Error GsymCreator::save(StringRef Path, llvm::endianness ByteOrder,
std::optional<uint64_t> SegmentSize) const {
if (SegmentSize)
return saveSegments(Path, ByteOrder, *SegmentSize);
@@ -187,35 +185,12 @@ llvm::Error GsymCreator::encode(FileWriter &O) const {
return ErrorSuccess();
}
-// Similar to std::remove_if, but the predicate is binary and it is passed both
-// the previous and the current element.
-template <class ForwardIt, class BinaryPredicate>
-static ForwardIt removeIfBinary(ForwardIt FirstIt, ForwardIt LastIt,
- BinaryPredicate Pred) {
- if (FirstIt != LastIt) {
- auto PrevIt = FirstIt++;
- FirstIt = std::find_if(FirstIt, LastIt, [&](const auto &Curr) {
- return Pred(*PrevIt++, Curr);
- });
- if (FirstIt != LastIt)
- for (ForwardIt CurrIt = FirstIt; ++CurrIt != LastIt;)
- if (!Pred(*PrevIt, *CurrIt)) {
- PrevIt = FirstIt;
- *FirstIt++ = std::move(*CurrIt);
- }
- }
- return FirstIt;
-}
-
llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
std::lock_guard<std::mutex> Guard(Mutex);
if (Finalized)
return createStringError(std::errc::invalid_argument, "already finalized");
Finalized = true;
- // Sort function infos so we can emit sorted functions.
- llvm::sort(Funcs);
-
// Don't let the string table indexes change by finalizing in order.
StrTab.finalizeInOrder();
@@ -239,83 +214,85 @@ llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
// Note that in case of (b), we cannot include Y in the result because then
// we wouldn't find any function for range (end of Y, end of X)
// with binary search
- auto NumBefore = Funcs.size();
- Funcs.erase(
- removeIfBinary(Funcs.begin(), Funcs.end(),
- [&](const auto &Prev, const auto &Curr) {
- // Empty ranges won't intersect, but we still need to
- // catch the case where we have multiple symbols at the
- // same address and coalesce them.
- const bool ranges_equal = Prev.Range == Curr.Range;
- if (ranges_equal || Prev.Range.intersects(Curr.Range)) {
- // Overlapping ranges or empty identical ranges.
- if (ranges_equal) {
- // Same address range. Check if one is from debug
- // info and the other is from a symbol table. If
- // so, then keep the one with debug info. Our
- // sorting guarantees that entries with matching
- // address ranges that have debug info are last in
- // the sort.
- if (Prev == Curr) {
- // FunctionInfo entries match exactly (range,
- // lines, inlines)
-
- // We used to output a warning here, but this was
- // so frequent on some binaries, in particular
- // when those were built with GCC, that it slowed
- // down processing extremely.
- return true;
- } else {
- if (!Prev.hasRichInfo() && Curr.hasRichInfo()) {
- // Same address range, one with no debug info
- // (symbol) and the next with debug info. Keep
- // the latter.
- return true;
- } else {
- if (!Quiet) {
- OS << "warning: same address range contains "
- "different debug "
- << "info. Removing:\n"
- << Prev << "\nIn favor of this one:\n"
- << Curr << "\n";
- }
- return true;
- }
- }
- } else {
- if (!Quiet) { // print warnings about overlaps
- OS << "warning: function ranges overlap:\n"
- << Prev << "\n"
- << Curr << "\n";
- }
- }
- } else if (Prev.Range.size() == 0 &&
- Curr.Range.contains(Prev.Range.start())) {
- if (!Quiet) {
- OS << "warning: removing symbol:\n"
- << Prev << "\nKeeping:\n"
- << Curr << "\n";
- }
- return true;
- }
-
- return false;
- }),
- Funcs.end());
-
- // If our last function info entry doesn't have a size and if we have valid
- // text ranges, we should set the size of the last entry since any search for
- // a high address might match our last entry. By fixing up this size, we can
- // help ensure we don't cause lookups to always return the last symbol that
- // has no size when doing lookups.
- if (!Funcs.empty() && Funcs.back().Range.size() == 0 && ValidTextRanges) {
- if (auto Range =
- ValidTextRanges->getRangeThatContains(Funcs.back().Range.start())) {
- Funcs.back().Range = {Funcs.back().Range.start(), Range->end()};
+
+ const auto NumBefore = Funcs.size();
+ // Only sort and unique if this isn't a segment. If this is a segment we
+ // already finalized the main GsymCreator with all of the function infos
+ // and then the already sorted and uniqued function infos were added to this
+ // object.
+ if (!IsSegment) {
+ if (NumBefore > 1) {
+ // Sort function infos so we can emit sorted functions.
+ llvm::sort(Funcs);
+ std::vector<FunctionInfo> FinalizedFuncs;
+ FinalizedFuncs.reserve(Funcs.size());
+ FinalizedFuncs.emplace_back(std::move(Funcs.front()));
+ for (size_t Idx=1; Idx < NumBefore; ++Idx) {
+ FunctionInfo &Prev = FinalizedFuncs.back();
+ FunctionInfo &Curr = Funcs[Idx];
+ // Empty ranges won't intersect, but we still need to
+ // catch the case where we have multiple symbols at the
+ // same address and coalesce them.
+ const bool ranges_equal = Prev.Range == Curr.Range;
+ if (ranges_equal || Prev.Range.intersects(Curr.Range)) {
+ // Overlapping ranges or empty identical ranges.
+ if (ranges_equal) {
+ // Same address range. Check if one is from debug
+ // info and the other is from a symbol table. If
+ // so, then keep the one with debug info. Our
+ // sorting guarantees that entries with matching
+ // 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";
+ }
+ }
+ // 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
+ OS << "warning: function ranges overlap:\n"
+ << Prev << "\n"
+ << Curr << "\n";
+ }
+ FinalizedFuncs.emplace_back(std::move(Curr));
+ }
+ } else {
+ if (Prev.Range.size() == 0 && Curr.Range.contains(Prev.Range.start())) {
+ // Symbols on macOS don't have address ranges, so if the range
+ // doesn't match and the size is zero, then we replace the empty
+ // symbol function info with the current one.
+ std::swap(Prev, Curr);
+ } else {
+ FinalizedFuncs.emplace_back(std::move(Curr));
+ }
+ }
+ }
+ std::swap(Funcs, FinalizedFuncs);
+ }
+ // If our last function info entry doesn't have a size and if we have valid
+ // text ranges, we should set the size of the last entry since any search for
+ // a high address might match our last entry. By fixing up this size, we can
+ // help ensure we don't cause lookups to always return the last symbol that
+ // has no size when doing lookups.
+ if (!Funcs.empty() && Funcs.back().Range.size() == 0 && ValidTextRanges) {
+ if (auto Range =
+ ValidTextRanges->getRangeThatContains(Funcs.back().Range.start())) {
+ Funcs.back().Range = {Funcs.back().Range.start(), Range->end()};
+ }
}
+ OS << "Pruned " << NumBefore - Funcs.size() << " functions, ended with "
+ << Funcs.size() << " total\n";
}
- OS << "Pruned " << NumBefore - Funcs.size() << " functions, ended with "
- << Funcs.size() << " total\n";
return Error::success();
}
@@ -355,7 +332,6 @@ uint32_t GsymCreator::insertString(StringRef S, bool Copy) {
void GsymCreator::addFunctionInfo(FunctionInfo &&FI) {
std::lock_guard<std::mutex> Guard(Mutex);
- Ranges.insert(FI.Range);
Funcs.emplace_back(std::move(FI));
}
@@ -388,31 +364,24 @@ bool GsymCreator::IsValidTextAddress(uint64_t Addr) const {
return true; // No valid text ranges has been set, so accept all ranges.
}
-bool GsymCreator::hasFunctionInfoForAddress(uint64_t Addr) const {
- std::lock_guard<std::mutex> Guard(Mutex);
- return Ranges.contains(Addr);
-}
-
std::optional<uint64_t> GsymCreator::getFirstFunctionAddress() const {
- if (Finalized && !Funcs.empty())
+ // If we have finalized then Funcs are sorted. If we are a segment then
+ // Funcs will be sorted as well since function infos get added from an
+ // already finalized GsymCreator object where its functions were sorted and
+ // uniqued.
+ if ((Finalized || IsSegment) && !Funcs.empty())
return std::optional<uint64_t>(Funcs.front().startAddress());
- // This code gets used by the segmentation of GSYM files to help determine the
- // size of the GSYM header while continually adding new FunctionInfo objects
- // to this object, so we haven't finalized this object yet.
- if (Ranges.empty())
- return std::nullopt;
- return std::optional<uint64_t>(Ranges.begin()->start());
+ return std::nullopt;
}
std::optional<uint64_t> GsymCreator::getLastFunctionAddress() const {
- if (Finalized && !Funcs.empty())
+ // If we have finalized then Funcs are sorted. If we are a segment then
+ // Funcs will be sorted as well since function infos get added from an
+ // already finalized GsymCreator object where its functions were sorted and
+ // uniqued.
+ if ((Finalized || IsSegment) && !Funcs.empty())
return std::optional<uint64_t>(Funcs.back().startAddress());
- // This code gets used by the segmentation of GSYM files to help determine the
- // size of the GSYM header while continually adding new FunctionInfo objects
- // to this object, so we haven't finalized this object yet.
- if (Ranges.empty())
- return std::nullopt;
- return std::optional<uint64_t>((Ranges.end() - 1)->end());
+ return std::nullopt;
}
std::optional<uint64_t> GsymCreator::getBaseAddress() const {
@@ -477,7 +446,6 @@ uint64_t GsymCreator::copyFunctionInfo(const GsymCreator &SrcGC, size_t FuncIdx)
// this GsymCreator and then copy the function info and update the string
// table offsets to match the new offsets.
const FunctionInfo &SrcFI = SrcGC.Funcs[FuncIdx];
- Ranges.insert(SrcFI.Range);
FunctionInfo DstFI;
DstFI.Range = SrcFI.Range;
@@ -503,12 +471,12 @@ uint64_t GsymCreator::copyFunctionInfo(const GsymCreator &SrcGC, size_t FuncIdx)
fixupInlineInfo(SrcGC, *DstFI.Inline);
}
std::lock_guard<std::mutex> Guard(Mutex);
- Funcs.push_back(DstFI);
+ Funcs.emplace_back(DstFI);
return Funcs.back().cacheEncoding();
}
llvm::Error GsymCreator::saveSegments(StringRef Path,
- llvm::support::endianness ByteOrder,
+ llvm::endianness ByteOrder,
uint64_t SegmentSize) const {
if (SegmentSize == 0)
return createStringError(std::errc::invalid_argument,
@@ -551,6 +519,10 @@ GsymCreator::createSegment(uint64_t SegmentSize, size_t &FuncIdx) const {
return std::unique_ptr<GsymCreator>();
std::unique_ptr<GsymCreator> GC(new GsymCreator(/*Quiet=*/true));
+
+ // Tell the creator that this is a segment.
+ GC->setIsSegment();
+
// Set the base address if there is one.
if (BaseAddress)
GC->setBaseAddress(*BaseAddress);