//===- GsymCreatorV2.cpp --------------------------------------------------===// // // 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 //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/GSYM/GsymCreatorV2.h" #include "llvm/DebugInfo/GSYM/FileWriter.h" #include "llvm/DebugInfo/GSYM/GlobalData.h" #include "llvm/DebugInfo/GSYM/HeaderV2.h" #include "llvm/Support/MathExtras.h" #include using namespace llvm; using namespace gsym; uint64_t GsymCreatorV2::calculateHeaderAndTableSize() const { const uint64_t HeaderSize = HeaderV2::getEncodedSize(); const size_t NumFuncs = Funcs.size(); const uint32_t NumEntries = 5 + (UUID.empty() ? 0 : 1) + 1; uint64_t Size = HeaderSize + NumEntries * 20; Size = llvm::alignTo(Size, getAddressOffsetSize()); Size += NumFuncs * getAddressOffsetSize(); Size = llvm::alignTo(Size, HeaderV2::getAddressInfoOffsetSize()); Size += NumFuncs * HeaderV2::getAddressInfoOffsetSize(); Size = llvm::alignTo(Size, 4); Size += 4 + Files.size() * FileEntry::getEncodedSize(getStringOffsetSize()); Size += StrTab.getSize(); Size += UUID.size(); return Size; } /// For V2 file layout, see HeaderV2.h llvm::Error GsymCreatorV2::encode(FileWriter &O) const { std::lock_guard Guard(Mutex); std::optional BaseAddr; if (auto Err = validateForEncoding(BaseAddr)) return Err; const uint8_t AddrOffSize = getAddressOffsetSize(); // Pre-encode all FunctionInfo objects into a temporary buffer so we know the // total FunctionInfo section size and each function's offset within it. SmallVector FIBuf; raw_svector_ostream FIOS(FIBuf); FileWriter FIFW(FIOS, O.getByteOrder()); FIFW.setStringOffsetSize(getStringOffsetSize()); std::vector FIRelativeOffsets; for (const auto &FI : Funcs) { if (auto OffOrErr = FI.encode(FIFW)) FIRelativeOffsets.push_back(*OffOrErr); else return OffOrErr.takeError(); } const uint64_t FISectionSize = FIBuf.size(); const uint64_t StringTableSize = StrTab.getSize(); const uint8_t StrpSize = 8; const bool HasUUID = !UUID.empty(); const uint32_t NumGlobalDataEntries = 5 + (HasUUID ? 1 : 0) + 1; const uint64_t GlobalDataArraySize = static_cast(NumGlobalDataEntries) * 20; const uint64_t HeaderSize = HeaderV2::getEncodedSize(); uint64_t CurOffset = HeaderSize + GlobalDataArraySize; // UUID section (first, no alignment requirement). const uint64_t UUIDOffset = CurOffset; const uint64_t UUIDSectionSize = UUID.size(); if (HasUUID) CurOffset += UUIDSectionSize; // AddrOffsets section. CurOffset = llvm::alignTo(CurOffset, AddrOffSize); const uint64_t AddrOffsetsOffset = CurOffset; const uint64_t AddrOffsetsSize = Funcs.size() * AddrOffSize; CurOffset += AddrOffsetsSize; // AddrInfoOffsets section. const uint8_t AddrInfoOffSize = 8; CurOffset = llvm::alignTo(CurOffset, AddrInfoOffSize); const uint64_t AddrInfoOffsetsOffset = CurOffset; const uint64_t AddrInfoOffsetsSize = Funcs.size() * AddrInfoOffSize; CurOffset += AddrInfoOffsetsSize; // FileTable section. CurOffset = llvm::alignTo(CurOffset, 4); const uint64_t FileTableOffset = CurOffset; const uint64_t FileTableSize = 4 + Files.size() * FileEntry::getEncodedSize(StrpSize); CurOffset += FileTableSize; // StringTable section. const uint64_t StringTableOffset = CurOffset; CurOffset += StringTableSize; // FunctionInfo section. CurOffset = llvm::alignTo(CurOffset, 4); const uint64_t FISectionOffset = CurOffset; CurOffset += FISectionSize; // Build and write the header. HeaderV2 Hdr; Hdr.Magic = GSYM_MAGIC; Hdr.Version = HeaderV2::getVersion(); Hdr.BaseAddress = *BaseAddr; Hdr.NumAddresses = static_cast(Funcs.size()); Hdr.AddrOffSize = AddrOffSize; Hdr.StrTableEncoding = StringTableEncoding::Default; if (auto Err = Hdr.encode(O)) return Err; // Write GlobalData entries. if (HasUUID) GlobalData{GlobalInfoType::UUID, UUIDOffset, UUIDSectionSize}.encode(O); GlobalData{GlobalInfoType::AddrOffsets, AddrOffsetsOffset, AddrOffsetsSize} .encode(O); GlobalData{GlobalInfoType::AddrInfoOffsets, AddrInfoOffsetsOffset, AddrInfoOffsetsSize} .encode(O); GlobalData{GlobalInfoType::FileTable, FileTableOffset, FileTableSize}.encode( O); GlobalData{GlobalInfoType::StringTable, StringTableOffset, StringTableSize} .encode(O); GlobalData{GlobalInfoType::FunctionInfo, FISectionOffset, FISectionSize} .encode(O); GlobalData{GlobalInfoType::EndOfList, 0, 0}.encode(O); // Write UUID section. if (HasUUID) { assert(O.tell() == UUIDOffset); O.writeData(ArrayRef(UUID.data(), UUID.size())); } // Write AddrOffsets section. O.alignTo(AddrOffSize); assert(O.tell() == AddrOffsetsOffset); encodeAddrOffsets(O, AddrOffSize, *BaseAddr); // Write AddrInfoOffsets section. Values are relative to FunctionInfo section. O.alignTo(AddrInfoOffSize); assert(O.tell() == AddrInfoOffsetsOffset); for (uint64_t RelOff : FIRelativeOffsets) O.writeU64(RelOff); // Write FileTable section. O.alignTo(4); assert(O.tell() == FileTableOffset); if (auto Err = encodeFileTable(O)) return Err; // Write StringTable section. assert(O.tell() == StringTableOffset); StrTab.write(O.get_stream()); // Write FunctionInfo section. O.alignTo(4); assert(O.tell() == FISectionOffset); O.writeData(ArrayRef(reinterpret_cast(FIBuf.data()), FIBuf.size())); return Error::success(); }