41 std::lock_guard<std::mutex> Guard(
Mutex);
42 const auto NextIndex = Files.size();
44 auto R = FileEntryToIndex.
insert(std::make_pair(FE, NextIndex));
46 Files.emplace_back(FE);
47 return R.first->second;
56 const FileEntry SrcFE = SrcGC.Files[FileIdx];
58 uint32_t Dir = StrTab.
add(SrcGC.StringOffsetMap.find(SrcFE.
Dir)->second);
61 return insertFileEntry(DstFE);
67 std::optional<uint64_t> SegmentSize)
const {
69 return saveSegments(Path, ByteOrder, *SegmentSize);
79 std::lock_guard<std::mutex> Guard(
Mutex);
82 "no functions to encode");
85 "GsymCreator wasn't finalized prior to encoding");
87 if (Funcs.size() > UINT32_MAX)
89 "too many FunctionInfos");
91 std::optional<uint64_t> BaseAddress = getBaseAddress();
95 "invalid base address");
105 memset(Hdr.
UUID, 0,
sizeof(Hdr.
UUID));
117 const uint64_t MaxAddressOffset = getMaxAddressOffset();
120 for (
const auto &FuncInfo : Funcs) {
126 assert(AddrOffset <= MaxAddressOffset);
127 (void)MaxAddressOffset;
130 O.writeU8(
static_cast<uint8_t
>(AddrOffset));
133 O.writeU16(
static_cast<uint16_t>(AddrOffset));
136 O.writeU32(
static_cast<uint32_t>(AddrOffset));
139 O.writeU64(AddrOffset);
146 const off_t AddrInfoOffsetsOffset = O.tell();
147 for (
size_t i = 0, n = Funcs.size(); i < n; ++i)
153 assert(Files[0].Dir == 0);
155 size_t NumFiles = Files.size();
156 if (NumFiles > UINT32_MAX)
158 O.writeU32(
static_cast<uint32_t>(NumFiles));
159 for (
auto File : Files) {
160 O.writeU32(File.Dir);
161 O.writeU32(File.Base);
165 const off_t StrtabOffset = O.tell();
166 StrTab.
write(O.get_stream());
167 const off_t StrtabSize = O.tell() - StrtabOffset;
168 std::vector<uint32_t> AddrInfoOffsets;
171 for (
const auto &FuncInfo : Funcs) {
173 AddrInfoOffsets.push_back(OffsetOrErr.get());
175 return OffsetOrErr.takeError();
183 for (
auto AddrInfoOffset : AddrInfoOffsets) {
184 O.fixup32(AddrInfoOffset, AddrInfoOffsetsOffset +
Offset);
191 std::lock_guard<std::mutex> Guard(
Mutex);
220 const auto NumBefore = Funcs.size();
229 std::vector<FunctionInfo> FinalizedFuncs;
230 FinalizedFuncs.reserve(Funcs.size());
231 FinalizedFuncs.emplace_back(std::move(Funcs.front()));
232 for (
size_t Idx=1;
Idx < NumBefore; ++
Idx) {
238 const bool ranges_equal = Prev.
Range == Curr.
Range;
248 if (!(Prev == Curr)) {
251 OS <<
"warning: same address range contains "
253 <<
"info. Removing:\n"
254 << Prev <<
"\nIn favor of this one:\n"
265 OS <<
"warning: function ranges overlap:\n"
269 FinalizedFuncs.emplace_back(std::move(Curr));
278 FinalizedFuncs.emplace_back(std::move(Curr));
289 if (!Funcs.empty() && Funcs.back().Range.size() == 0 && ValidTextRanges) {
291 ValidTextRanges->getRangeThatContains(Funcs.back().Range.start())) {
292 Funcs.back().Range = {Funcs.back().Range.start(), Range->end()};
295 OS <<
"Pruned " << NumBefore - Funcs.size() <<
" functions, ended with "
296 << Funcs.size() <<
" total\n";
305 return StrTab.
add(SrcGC.StringOffsetMap.find(StrOff)->second);
314 std::lock_guard<std::mutex> Guard(
Mutex);
330 if (StringOffsetMap.count(StrOff) == 0)
331 StringOffsetMap.insert(std::make_pair(StrOff, CHStr));
336 std::lock_guard<std::mutex> Guard(
Mutex);
337 Funcs.emplace_back(std::move(FI));
342 std::lock_guard<std::mutex> Guard(
Mutex);
343 for (
auto &FI : Funcs) {
350 std::function<
bool(
const FunctionInfo &)>
const &Callback)
const {
351 std::lock_guard<std::mutex> Guard(
Mutex);
352 for (
const auto &FI : Funcs) {
359 std::lock_guard<std::mutex> Guard(
Mutex);
365 return ValidTextRanges->contains(
Addr);
369std::optional<uint64_t> GsymCreator::getFirstFunctionAddress()
const {
374 if ((Finalized || IsSegment) && !Funcs.empty())
375 return std::optional<uint64_t>(Funcs.front().startAddress());
379std::optional<uint64_t> GsymCreator::getLastFunctionAddress()
const {
384 if ((Finalized || IsSegment) && !Funcs.empty())
385 return std::optional<uint64_t>(Funcs.back().startAddress());
389std::optional<uint64_t> GsymCreator::getBaseAddress()
const {
392 return getFirstFunctionAddress();
395uint64_t GsymCreator::getMaxAddressOffset()
const {
396 switch (getAddressOffsetSize()) {
397 case 1:
return UINT8_MAX;
398 case 2:
return UINT16_MAX;
399 case 4:
return UINT32_MAX;
405uint8_t GsymCreator::getAddressOffsetSize()
const {
406 const std::optional<uint64_t> BaseAddress = getBaseAddress();
407 const std::optional<uint64_t> LastFuncAddr = getLastFunctionAddress();
408 if (BaseAddress && LastFuncAddr) {
409 const uint64_t AddrDelta = *LastFuncAddr - *BaseAddress;
410 if (AddrDelta <= UINT8_MAX)
412 else if (AddrDelta <= UINT16_MAX)
414 else if (AddrDelta <= UINT32_MAX)
421uint64_t GsymCreator::calculateHeaderAndTableSize()
const {
423 const size_t NumFuncs = Funcs.size();
425 Size += NumFuncs * getAddressOffsetSize();
440 II.
Name = copyString(SrcGC, II.
Name);
443 fixupInlineInfo(SrcGC, ChildII);
454 DstFI.
Name = copyString(SrcGC, SrcFI.
Name);
462 const size_t NumLines = DstLT.
size();
463 for (
size_t I=0;
I<NumLines; ++
I) {
465 LE.File = copyFile(SrcGC,
LE.File);
473 fixupInlineInfo(SrcGC, *DstFI.
Inline);
475 std::lock_guard<std::mutex> Guard(
Mutex);
476 Funcs.emplace_back(DstFI);
477 return Funcs.back().cacheEncoding();
483 if (SegmentSize == 0)
485 "invalid segment size zero");
488 const size_t NumFuncs = Funcs.size();
489 while (FuncIdx < NumFuncs) {
500 std::string SegmentedGsymPath;
502 std::optional<uint64_t> FirstFuncAddr =
GC->getFirstFunctionAddress();
506 Err =
GC->save(SegmentedGsymPath, ByteOrder, std::nullopt);
520 if (FuncIdx >= Funcs.size())
521 return std::unique_ptr<GsymCreator>();
523 std::unique_ptr<GsymCreator> GC(
new GsymCreator(
true));
530 GC->setBaseAddress(*BaseAddress);
533 const size_t NumFuncs = Funcs.size();
538 for (; FuncIdx < NumFuncs; ++FuncIdx) {
539 const uint64_t HeaderAndTableSize = GC->calculateHeaderAndTableSize();
540 if (HeaderAndTableSize + SegmentFuncInfosSize >= SegmentSize) {
541 if (SegmentFuncInfosSize == 0)
543 "a segment size of %" PRIu64
" is to small to "
544 "fit any function infos, specify a larger value",
549 SegmentFuncInfosSize +=
alignTo(GC->copyFunctionInfo(*
this, FuncIdx), 4);
551 return std::move(GC);
#define offsetof(TYPE, MEMBER)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
std::pair< llvm::MachO::Target, std::string > UUID
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.
std::pair< typename Base::iterator, bool > insert(StringRef key)
Utility for building string tables with deduplicated suffixes.
void finalizeInOrder()
Finalize the string table without reording it.
bool contains(StringRef S) const
Check if a string is contained in the string table.
void write(raw_ostream &OS) const
size_t add(CachedHashStringRef S)
Add a string to the builder.
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.
void addFunctionInfo(FunctionInfo &&FI)
Add a function info to this GSYM creator.
uint32_t insertString(StringRef S, bool Copy=true)
Insert a string into the GSYM string table.
llvm::Error finalize(llvm::raw_ostream &OS)
Finalize the data in the GSYM creator prior to saving the data out.
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::Error encode(FileWriter &O) const
Encode a GSYM into the file writer stream at the current position.
llvm::Error save(StringRef Path, llvm::support::endianness ByteOrder, std::optional< uint64_t > SegmentSize=std::nullopt) const
Save a GSYM file to a stand alone file.
uint32_t insertFile(StringRef Path, sys::path::Style Style=sys::path::Style::native)
Insert a file into this GSYM creator.
size_t getNumFunctionInfos() const
Get the current number of FunctionInfo objects contained in this object.
bool IsValidTextAddress(uint64_t Addr) const
Check if an address is a valid code address.
void forEachFunctionInfo(std::function< bool(FunctionInfo &)> const &Callback)
Thread safe iteration over all function infos.
GsymCreator(bool Quiet=false)
LineTable class contains deserialized versions of line tables for each function's address ranges.
LineEntry & get(size_t i)
A raw_ostream that writes to a file descriptor.
A raw_ostream that discards all output.
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
#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
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
StringRef parent_path(StringRef path, Style style=Style::native)
Get parent path.
This is an optimization pass for GlobalISel generic memory operations.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
void sort(IteratorTy Start, IteratorTy End)
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.
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
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.
std::vector< InlineInfo > Children
uint32_t CallFile
1 based file index in the file table.
uint32_t Name
String table offset in the string table.
Line entries are used to encode the line tables in FunctionInfo objects.