blob: 8b7e8e7a270680dcfdaa97615b88c2b5592a0963 [file] [edit]
//===- 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();
}