42 std::lock_guard<std::mutex> Guard(
Mutex);
43 const auto NextIndex = Files.size();
45 auto R = FileEntryToIndex.
insert(std::make_pair(FE, NextIndex));
47 Files.emplace_back(FE);
48 return R.first->second;
57 const FileEntry SrcFE = SrcGC.Files[FileIdx];
62 : StrTab.
add(SrcGC.StringOffsetMap.find(SrcFE.
Dir)->second);
65 return insertFileEntry(DstFE);
69 std::optional<uint64_t> SegmentSize)
const {
71 return saveSegments(Path, ByteOrder, *SegmentSize);
81 std::lock_guard<std::mutex> Guard(Mutex);
84 "no functions to encode");
87 "GsymCreator wasn't finalized prior to encoding");
89 if (Funcs.size() > UINT32_MAX)
91 "too many FunctionInfos");
93 std::optional<uint64_t> BaseAddress = getBaseAddress();
97 "invalid base address");
107 memset(Hdr.
UUID, 0,
sizeof(Hdr.
UUID));
108 if (UUID.size() >
sizeof(Hdr.
UUID))
110 "invalid UUID size %u", (
uint32_t)UUID.size());
113 memcpy(Hdr.
UUID, UUID.data(), UUID.size());
119 const uint64_t MaxAddressOffset = getMaxAddressOffset();
122 for (
const auto &FuncInfo : Funcs) {
128 assert(AddrOffset <= MaxAddressOffset);
129 (void)MaxAddressOffset;
132 O.writeU8(
static_cast<uint8_t>(AddrOffset));
135 O.writeU16(
static_cast<uint16_t>(AddrOffset));
138 O.writeU32(
static_cast<uint32_t>(AddrOffset));
141 O.writeU64(AddrOffset);
148 const off_t AddrInfoOffsetsOffset = O.tell();
149 for (
size_t i = 0, n = Funcs.size(); i < n; ++i)
155 assert(Files[0].Dir == 0);
157 size_t NumFiles = Files.size();
158 if (NumFiles > UINT32_MAX)
160 O.writeU32(
static_cast<uint32_t>(NumFiles));
161 for (
auto File : Files) {
162 O.writeU32(File.Dir);
163 O.writeU32(File.Base);
167 const off_t StrtabOffset = O.tell();
168 StrTab.write(O.get_stream());
169 const off_t StrtabSize = O.tell() - StrtabOffset;
170 std::vector<uint32_t> AddrInfoOffsets;
174 if (StrtabSize > UINT32_MAX) {
176 "string table size exceeded 32-bit max");
180 for (
const auto &FuncInfo : Funcs) {
184 if (
Offset > UINT32_MAX) {
186 "address info offset exceeded 32-bit max");
189 AddrInfoOffsets.push_back(
Offset);
191 return OffsetOrErr.takeError();
199 for (
auto AddrInfoOffset : AddrInfoOffsets) {
200 O.fixup32(AddrInfoOffset, AddrInfoOffsetsOffset +
Offset);
214 if (Funcs.size() < 2)
219 std::vector<FunctionInfo> TopLevelFuncs;
222 TopLevelFuncs.emplace_back(std::move(Funcs.front()));
227 for (
size_t Idx = 1; Idx < Funcs.size(); ++Idx) {
240 std::move(MatchFunc));
243 TopLevelFuncs.emplace_back(std::move(MatchFunc));
246 uint32_t mergedCount = Funcs.size() - TopLevelFuncs.size();
248 if (mergedCount != 0)
249 Out <<
"Have " << mergedCount
250 <<
" merged functions as children of other functions\n";
256 std::lock_guard<std::mutex> Guard(Mutex);
262 StrTab.finalizeInOrder();
285 const auto NumBefore = Funcs.size();
295 std::vector<FunctionInfo> FinalizedFuncs;
296 FinalizedFuncs.reserve(Funcs.size());
297 FinalizedFuncs.emplace_back(std::move(Funcs.front()));
298 for (
size_t Idx=1; Idx < NumBefore; ++Idx) {
304 const bool ranges_equal = Prev.
Range == Curr.
Range;
314 if (!(Prev == Curr)) {
317 "Duplicate address ranges with different debug info.",
319 OS <<
"warning: same address range contains "
321 <<
"info. Removing:\n"
322 << Prev <<
"\nIn favor of this one:\n"
334 OS <<
"warning: function ranges overlap:\n"
338 FinalizedFuncs.emplace_back(std::move(Curr));
347 FinalizedFuncs.emplace_back(std::move(Curr));
358 if (!Funcs.empty() && Funcs.back().Range.size() == 0 && ValidTextRanges) {
360 ValidTextRanges->getRangeThatContains(Funcs.back().Range.start())) {
361 Funcs.back().Range = {Funcs.back().Range.start(),
Range->end()};
364 Out <<
"Pruned " << NumBefore - Funcs.size() <<
" functions, ended with "
365 << Funcs.size() <<
" total\n";
374 return StrTab.
add(SrcGC.StringOffsetMap.find(StrOff)->second);
383 std::lock_guard<std::mutex> Guard(Mutex);
391 if (!StrTab.contains(CHStr))
395 const uint32_t StrOff = StrTab.add(CHStr);
399 StringOffsetMap.try_emplace(StrOff, CHStr);
404 auto I = StringOffsetMap.find(
Offset);
405 assert(
I != StringOffsetMap.end() &&
406 "GsymCreator::getString expects a valid offset as parameter.");
407 return I->second.val();
411 std::lock_guard<std::mutex> Guard(Mutex);
412 Funcs.emplace_back(std::move(FI));
417 std::lock_guard<std::mutex> Guard(Mutex);
418 for (
auto &FI : Funcs) {
425 std::function<
bool(
const FunctionInfo &)>
const &Callback)
const {
426 std::lock_guard<std::mutex> Guard(Mutex);
427 for (
const auto &FI : Funcs) {
434 std::lock_guard<std::mutex> Guard(Mutex);
440 return ValidTextRanges->contains(Addr);
444std::optional<uint64_t> GsymCreator::getFirstFunctionAddress()
const {
449 if ((Finalized || IsSegment) && !Funcs.empty())
450 return std::optional<uint64_t>(Funcs.front().startAddress());
454std::optional<uint64_t> GsymCreator::getLastFunctionAddress()
const {
459 if ((Finalized || IsSegment) && !Funcs.empty())
460 return std::optional<uint64_t>(Funcs.back().startAddress());
464std::optional<uint64_t> GsymCreator::getBaseAddress()
const {
467 return getFirstFunctionAddress();
470uint64_t GsymCreator::getMaxAddressOffset()
const {
471 switch (getAddressOffsetSize()) {
472 case 1:
return UINT8_MAX;
473 case 2:
return UINT16_MAX;
474 case 4:
return UINT32_MAX;
480uint8_t GsymCreator::getAddressOffsetSize()
const {
481 const std::optional<uint64_t> BaseAddress = getBaseAddress();
482 const std::optional<uint64_t> LastFuncAddr = getLastFunctionAddress();
483 if (BaseAddress && LastFuncAddr) {
484 const uint64_t AddrDelta = *LastFuncAddr - *BaseAddress;
485 if (AddrDelta <= UINT8_MAX)
487 else if (AddrDelta <= UINT16_MAX)
489 else if (AddrDelta <= UINT32_MAX)
496uint64_t GsymCreator::calculateHeaderAndTableSize()
const {
497 uint64_t
Size =
sizeof(Header);
498 const size_t NumFuncs = Funcs.size();
500 Size += NumFuncs * getAddressOffsetSize();
502 Size += NumFuncs *
sizeof(uint32_t);
504 Size += Files.size() *
sizeof(FileEntry);
506 Size += StrTab.getSize();
515 II.Name = copyString(SrcGC,
II.Name);
516 II.CallFile = copyFile(SrcGC,
II.CallFile);
517 for (
auto &ChildII:
II.Children)
518 fixupInlineInfo(SrcGC, ChildII);
521uint64_t GsymCreator::copyFunctionInfo(
const GsymCreator &SrcGC,
size_t FuncIdx) {
525 const FunctionInfo &SrcFI = SrcGC.Funcs[FuncIdx];
529 DstFI.
Name = copyString(SrcGC, SrcFI.
Name);
537 const size_t NumLines = DstLT.
size();
538 for (
size_t I=0;
I<NumLines; ++
I) {
539 LineEntry &
LE = DstLT.
get(
I);
540 LE.File = copyFile(SrcGC,
LE.File);
548 fixupInlineInfo(SrcGC, *DstFI.
Inline);
550 std::lock_guard<std::mutex> Guard(Mutex);
551 Funcs.emplace_back(DstFI);
552 return Funcs.back().cacheEncoding();
555llvm::Error GsymCreator::saveSegments(StringRef Path,
557 uint64_t SegmentSize)
const {
558 if (SegmentSize == 0)
560 "invalid segment size zero");
563 const size_t NumFuncs = Funcs.size();
564 while (FuncIdx < NumFuncs) {
565 llvm::Expected<std::unique_ptr<GsymCreator>> ExpectedGC =
572 OutputAggregator Out(
nullptr);
576 std::string SegmentedGsymPath;
577 raw_string_ostream SGP(SegmentedGsymPath);
578 std::optional<uint64_t> FirstFuncAddr =
GC->getFirstFunctionAddress();
581 Err =
GC->save(SegmentedGsymPath, ByteOrder, std::nullopt);
592llvm::Expected<std::unique_ptr<GsymCreator>>
595 if (FuncIdx >= Funcs.size())
596 return std::unique_ptr<GsymCreator>();
598 std::unique_ptr<GsymCreator> GC(
new GsymCreator(
true));
605 GC->setBaseAddress(*BaseAddress);
608 const size_t NumFuncs = Funcs.size();
613 for (; FuncIdx < NumFuncs; ++FuncIdx) {
614 const uint64_t HeaderAndTableSize = GC->calculateHeaderAndTableSize();
615 if (HeaderAndTableSize + SegmentFuncInfosSize >= SegmentSize) {
616 if (SegmentFuncInfosSize == 0)
618 "a segment size of %" PRIu64
" is to small to "
619 "fit any function infos, specify a larger value",
624 SegmentFuncInfosSize +=
alignTo(GC->copyFunctionInfo(*
this, FuncIdx), 4);
626 return std::move(GC);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define offsetof(TYPE, MEMBER)
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
bool intersects(const AddressRange &R) const
bool contains(uint64_t Addr) const
A container which contains a StringRef plus a precomputed hash.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Subclass of Error for the sole purpose of identifying the success path in the type system.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
reference get()
Returns a reference to the stored T value.
StringRef - Represent a constant reference to a string, i.e.
constexpr bool empty() const
empty - Check if the string is empty.
Utility for building string tables with deduplicated suffixes.
LLVM_ABI size_t add(CachedHashStringRef S, uint8_t Priority=0)
Add a string to the builder.
LLVM_ABI llvm::Error loadYAML(StringRef YAMLFile)
This method reads the specified YAML file, parses its content, and updates the Funcs vector with call...
A simplified binary data writer class that doesn't require targets, target definitions,...
GsymCreator is used to emit GSYM data to a stand alone file or section within a file.
LLVM_ABI void addFunctionInfo(FunctionInfo &&FI)
Add a function info to this GSYM creator.
LLVM_ABI uint32_t insertString(StringRef S, bool Copy=true)
Insert a string into the GSYM string table.
LLVM_ABI llvm::Expected< std::unique_ptr< GsymCreator > > createSegment(uint64_t SegmentSize, size_t &FuncIdx) const
Create a segmented GSYM creator starting with function info index FuncIdx.
LLVM_ABI llvm::Error save(StringRef Path, llvm::endianness ByteOrder, std::optional< uint64_t > SegmentSize=std::nullopt) const
Save a GSYM file to a stand alone file.
LLVM_ABI void prepareMergedFunctions(OutputAggregator &Out)
Organize merged FunctionInfo's.
LLVM_ABI StringRef getString(uint32_t Offset)
Retrieve a string from the GSYM string table given its offset.
LLVM_ABI llvm::Error loadCallSitesFromYAML(StringRef YAMLFile)
Load call site information from a YAML file.
LLVM_ABI llvm::Error encode(FileWriter &O) const
Encode a GSYM into the file writer stream at the current position.
LLVM_ABI llvm::Error finalize(OutputAggregator &OS)
Finalize the data in the GSYM creator prior to saving the data out.
LLVM_ABI uint32_t insertFile(StringRef Path, sys::path::Style Style=sys::path::Style::native)
Insert a file into this GSYM creator.
LLVM_ABI size_t getNumFunctionInfos() const
Get the current number of FunctionInfo objects contained in this object.
LLVM_ABI bool IsValidTextAddress(uint64_t Addr) const
Check if an address is a valid code address.
LLVM_ABI void forEachFunctionInfo(std::function< bool(FunctionInfo &)> const &Callback)
Thread safe iteration over all function infos.
LLVM_ABI GsymCreator(bool Quiet=false)
LineEntry & get(size_t i)
void Report(StringRef s, std::function< void(raw_ostream &o)> detailCallback)
A raw_ostream that writes to a file descriptor.
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr uint32_t GSYM_MAGIC
constexpr uint32_t GSYM_VERSION
LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
SmartMutex< false > Mutex
Mutex - A standard, always enforced mutex.
This is an optimization pass for GlobalISel generic memory operations.
void stable_sort(R &&Range)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false)
format_hex - Output N as a fixed width hexadecimal.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Files in GSYM are contained in FileEntry structs where we split the directory and basename into two d...
uint32_t Dir
Offsets in the string table.
Function information in GSYM files encodes information for one contiguous address range.
std::optional< InlineInfo > Inline
std::optional< MergedFunctionsInfo > MergedFunctions
bool hasRichInfo() const
Query if a FunctionInfo has rich debug info.
uint32_t Name
String table offset in the string table.
std::optional< LineTable > OptLineTable
Inline information stores the name of the inline function along with an array of address ranges.