| //===- 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 <cassert> | |
| 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<std::mutex> Guard(Mutex); | |
| std::optional<uint64_t> 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<char, 0> FIBuf; | |
| raw_svector_ostream FIOS(FIBuf); | |
| FileWriter FIFW(FIOS, O.getByteOrder()); | |
| FIFW.setStringOffsetSize(getStringOffsetSize()); | |
| std::vector<uint64_t> 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<uint64_t>(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<uint32_t>(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<uint8_t>(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<uint8_t>(reinterpret_cast<const uint8_t *>(FIBuf.data()), | |
| FIBuf.size())); | |
| return Error::success(); | |
| } |