39 : Obj(Obj), ErrHandler(EH) {
42 StringTable.append(4,
char(0));
45 bool useBigObj()
const {
46 return static_cast<int32_t
>(Obj.Sections.size()) >
50 bool isPE()
const {
return Obj.OptionalHeader.has_value(); }
53 uint32_t getFileAlignment()
const {
54 return Obj.OptionalHeader->Header.FileAlignment;
57 unsigned getSymbolSize()
const {
61 bool parseSections() {
62 for (COFFYAML::Section &Sec : Obj.Sections) {
72 std::string str =
utostr(Index);
74 ErrHandler(
"string table got too large");
83 ErrHandler(
"section alignment is too large");
87 ErrHandler(
"section alignment is not a power of 2");
97 for (COFFYAML::Symbol &Sym : Obj.Symbols) {
117 if (!parseSections())
125 auto [It,
Inserted] = StringTableMap.try_emplace(Str, StringTable.size());
127 StringTable.append(Str.begin(), Str.end());
128 StringTable.push_back(0);
133 COFFYAML::Object &Obj;
135 codeview::StringsAndChecksums StringsAndChecksums;
137 StringMap<unsigned> StringTableMap;
138 std::string StringTable;
139 uint32_t SectionTableStart;
140 uint32_t SectionTableSize;
145enum { DOSStubSize = 128 };
153 ExitOnError Err(
"Error occurred writing .debug$S section");
157 std::vector<DebugSubsectionRecordBuilder> Builders;
159 for (
auto &SS : CVSS) {
160 DebugSubsectionRecordBuilder
B(SS);
161 Size +=
B.calculateSerializedLength();
162 Builders.push_back(std::move(
B));
169 for (
const auto &
B : Builders) {
170 Err(
B.commit(Writer, CodeViewContainer::ObjectFile));
180 if (S.
Name ==
".debug$S") {
182 "Object file does not have debug string table!");
184 }
else if (S.
Name ==
".debug$T") {
186 }
else if (S.
Name ==
".debug$P") {
188 }
else if (S.
Name ==
".debug$H" && S.
DebugH) {
195 HasContent |=
E.size() != 0;
201 const std::vector<BBAddrMapYAML::PGOAnalysisMapEntry> *PGOAnalyses =
nullptr;
205 ".llvm_bb_addr_map when Entries does not exist";
208 "in .llvm_bb_addr_map";
223 E.writeAsBinary(CBA);
227 LittleEndian, CP.is64Bit() ? 8 : 4);
237 memset(Header, 0,
sizeof(*Header));
238 Header->Magic = Magic;
239 Header->SectionAlignment = CP.Obj.
OptionalHeader->Header.SectionAlignment;
240 Header->FileAlignment = CP.Obj.
OptionalHeader->Header.FileAlignment;
241 uint32_t SizeOfCode = 0, SizeOfInitializedData = 0,
242 SizeOfUninitializedData = 0;
243 uint32_t SizeOfHeaders =
alignTo(CP.SectionTableStart + CP.SectionTableSize,
244 Header->FileAlignment);
245 uint32_t SizeOfImage =
alignTo(SizeOfHeaders, Header->SectionAlignment);
254 if (S.
Name ==
".text")
256 else if (S.
Name ==
".data")
261 Header->SizeOfCode = SizeOfCode;
262 Header->SizeOfInitializedData = SizeOfInitializedData;
263 Header->SizeOfUninitializedData = SizeOfUninitializedData;
264 Header->AddressOfEntryPoint =
267 Header->MajorOperatingSystemVersion =
269 Header->MinorOperatingSystemVersion =
271 Header->MajorImageVersion = CP.Obj.
OptionalHeader->Header.MajorImageVersion;
272 Header->MinorImageVersion = CP.Obj.
OptionalHeader->Header.MinorImageVersion;
273 Header->MajorSubsystemVersion =
275 Header->MinorSubsystemVersion =
277 Header->SizeOfImage = SizeOfImage;
278 Header->SizeOfHeaders = SizeOfHeaders;
280 Header->DLLCharacteristics = CP.Obj.
OptionalHeader->Header.DLLCharacteristics;
281 Header->SizeOfStackReserve = CP.Obj.
OptionalHeader->Header.SizeOfStackReserve;
282 Header->SizeOfStackCommit = CP.Obj.
OptionalHeader->Header.SizeOfStackCommit;
283 Header->SizeOfHeapReserve = CP.Obj.
OptionalHeader->Header.SizeOfHeapReserve;
284 Header->SizeOfHeapCommit = CP.Obj.
OptionalHeader->Header.SizeOfHeapCommit;
285 Header->NumberOfRvaAndSize = CP.Obj.
OptionalHeader->Header.NumberOfRvaAndSize;
295 NumberOfAuxSymbols += 1;
297 NumberOfAuxSymbols += 1;
299 NumberOfAuxSymbols += 1;
301 NumberOfAuxSymbols +=
302 (Sym.
File.
size() + CP.getSymbolSize() - 1) / CP.getSymbolSize();
304 NumberOfAuxSymbols += 1;
306 NumberOfAuxSymbols += 1;
321 uint64_t PointerToSymbolTableOffset;
326 memset(&DH, 0,
sizeof(DH));
339 CBA.
write(
reinterpret_cast<const char *
>(&DH),
sizeof(DH));
346 if (CP.useBigObj()) {
357 PointerToSymbolTableOffset = CBA.
getOffset();
366 PointerToSymbolTableOffset = CBA.
getOffset();
382 const std::optional<COFF::DataDirectory> *DataDirectories =
385 if (
I >= NumDataDir || !DataDirectories[
I]) {
388 CBA.
write(DataDirectories[
I]->RelativeVirtualAddress, LittleEndian);
389 CBA.
write(DataDirectories[
I]->
Size, LittleEndian);
400 unsigned CurSymbol = 0;
403 SymbolTableIndexMap[Sym.
Name] = CurSymbol;
413 CP.StringsAndChecksums);
439 if (R.SymbolTableIndex) {
440 if (!R.SymbolName.empty())
442 <<
"Both SymbolName and SymbolTableIndex specified\n";
443 SymbolTableIndex = *R.SymbolTableIndex;
445 SymbolTableIndex = SymbolTableIndexMap[R.SymbolName];
447 CBA.
write(R.VirtualAddress, LittleEndian);
448 CBA.
write(SymbolTableIndex, LittleEndian);
449 CBA.
write(R.Type, LittleEndian);
458 CBA.
updateDataAt(OptionalHeaderOffset, &PEH,
sizeof(PEH));
464 CBA.
updateDataAt(OptionalHeaderOffset, &PEH,
sizeof(PEH));
470 "unexpected COFF section header size");
471 uint64_t SectionHeaderOffset = CP.SectionTableStart;
484 CBA.
updateDataAt(SectionHeaderOffset, &Header,
sizeof(Header));
485 SectionHeaderOffset +=
sizeof(Header);
497 for (std::vector<COFFYAML::Symbol>::const_iterator i = CP.Obj.
Symbols.begin(),
501 CBA.
write(i->Header.Value, LittleEndian);
503 CBA.
write(i->Header.SectionNumber, LittleEndian);
505 CBA.
write(
static_cast<int16_t
>(i->Header.SectionNumber), LittleEndian);
506 CBA.
write(i->Header.Type, LittleEndian);
507 CBA.
write(i->Header.StorageClass, LittleEndian);
508 CBA.
write(i->Header.NumberOfAuxSymbols, LittleEndian);
510 if (i->FunctionDefinition) {
511 CBA.
write(i->FunctionDefinition->TagIndex, LittleEndian);
512 CBA.
write(i->FunctionDefinition->TotalSize, LittleEndian);
513 CBA.
write(i->FunctionDefinition->PointerToLinenumber, LittleEndian);
514 CBA.
write(i->FunctionDefinition->PointerToNextFunction, LittleEndian);
515 CBA.
writeZeros(
sizeof(i->FunctionDefinition->unused));
518 if (i->bfAndefSymbol) {
519 CBA.
writeZeros(
sizeof(i->bfAndefSymbol->unused1));
520 CBA.
write(i->bfAndefSymbol->Linenumber, LittleEndian);
521 CBA.
writeZeros(
sizeof(i->bfAndefSymbol->unused2));
522 CBA.
write(i->bfAndefSymbol->PointerToNextFunction, LittleEndian);
523 CBA.
writeZeros(
sizeof(i->bfAndefSymbol->unused3));
526 if (i->WeakExternal) {
527 CBA.
write(i->WeakExternal->TagIndex, LittleEndian);
528 CBA.
write(i->WeakExternal->Characteristics, LittleEndian);
529 CBA.
writeZeros(
sizeof(i->WeakExternal->unused));
532 if (!i->File.empty()) {
533 unsigned SymbolSize = CP.getSymbolSize();
535 (i->File.size() + SymbolSize - 1) / SymbolSize;
536 uint32_t NumberOfAuxBytes = NumberOfAuxRecords * SymbolSize;
537 uint32_t NumZeros = NumberOfAuxBytes - i->File.size();
538 CBA.
write(i->File.data(), i->File.size());
541 if (i->SectionDefinition) {
542 CBA.
write(i->SectionDefinition->Length, LittleEndian);
543 CBA.
write(i->SectionDefinition->NumberOfRelocations, LittleEndian);
544 CBA.
write(i->SectionDefinition->NumberOfLinenumbers, LittleEndian);
545 CBA.
write(i->SectionDefinition->CheckSum, LittleEndian);
546 CBA.
write(
static_cast<int16_t
>(i->SectionDefinition->Number),
548 CBA.
write(i->SectionDefinition->Selection, LittleEndian);
549 CBA.
writeZeros(
sizeof(i->SectionDefinition->unused));
550 CBA.
write(
static_cast<int16_t
>(i->SectionDefinition->Number >> 16),
555 CBA.
write(i->CLRToken->AuxType, LittleEndian);
557 CBA.
write(i->CLRToken->SymbolTableIndex, LittleEndian);
566 CP.StringTable.size();
567 CBA.
write(CP.StringTable.data(), CP.StringTable.size());
575 Size +=
sizeof(*UInt32);
585 CBA.
write(
reinterpret_cast<const char *
>(&S),
586 std::min(
sizeof(S),
static_cast<size_t>(S.Size)));
587 if (
sizeof(S) < S.Size)
607 COFFParser CP(Doc, ErrHandler);
609 ErrHandler(
"failed to parse YAML file");
616 ErrHandler(
"failed to write COFF file");
622 ErrHandler(
"the desired output size is greater than permitted. Use the "
623 "--max-size option to change the limit");
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the StringMap class.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool writeCOFF(COFFParser &CP, ContiguousBlobAccumulator &CBA)
static yaml::BinaryRef toDebugS(ArrayRef< CodeViewYAML::YAMLDebugSubsection > Subsections, const codeview::StringsAndChecksums &SC, BumpPtrAllocator &Allocator)
static void writeLoadConfig(T &S, ContiguousBlobAccumulator &CBA)
static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic, T Header)
static bool writeSectionContent(COFFParser &CP, COFFYAML::Section &S, ContiguousBlobAccumulator &CBA)
This file defines ContiguousBlobAccumulator, the size-limited output buffer shared by the yaml2obj em...
static size_t getStringIndex(StringRef Name)
static llvm::Error parse(GsymDataExtractor &Data, uint64_t BaseAddr, LineEntryCallback const &Callback)
static bool is64Bit(const char *name)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Provides write only access to a subclass of WritableBinaryStream.
Error writeInteger(T Value)
Write the integer Value to the underlying stream in the specified endianness.
Lightweight error class with error context and mandatory checking.
Helper for check-and-exit error handling.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
constexpr bool empty() const
Check if the string is empty.
constexpr size_t size() const
Get the string size.
static LLVM_ABI raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
static LLVM_ABI raw_ostream & error()
Convenience method for printing "error: " to stderr.
bool hasChecksums() const
This class implements an extremely fast bulk output stream that can only output to a stream.
Specialized YAMLIO scalar type for representing a binary blob.
ArrayRef< uint8_t >::size_type binary_size() const
The number of bytes that are represented by this BinaryRef.
LLVM_ABI uint64_t padToAlignment(unsigned Align)
LLVM_ABI void writeAsBinary(const BinaryRef &Bin, uint64_t N=UINT64_MAX)
void writeBlobToStream(raw_ostream &Out) const
void write(const char *Ptr, size_t Size)
uint64_t getOffset() const
void writeZeros(uint64_t Num)
void updateDataAt(uint64_t Pos, T Val, llvm::endianness E)
LLVM_ABI void encodePayload(ArrayRef< BBAddrMapEntry > Entries, const std::vector< PGOAnalysisMapEntry > *PGOAnalyses, yaml::ContiguousBlobAccumulator &CBA, llvm::endianness Endian, unsigned AddressSize)
Encodes the BBAddrMap payload into CBA.
@ IMAGE_FILE_MACHINE_UNKNOWN
@ IMAGE_SCN_CNT_UNINITIALIZED_DATA
@ IMAGE_SCN_CNT_INITIALIZED_DATA
@ IMAGE_SCN_LNK_NRELOC_OVFL
const int32_t MaxNumberOfSections16
static const char BigObjMagic[]
static const char PEMagic[]
@ SCT_COMPLEX_TYPE_SHIFT
Type is formed as (base + (derived << SCT_COMPLEX_TYPE_SHIFT))
LLVM_ABI void initializeStringsAndChecksums(ArrayRef< YAMLDebugSubsection > Sections, codeview::StringsAndChecksums &SC)
LLVM_ABI Expected< std::vector< std::shared_ptr< codeview::DebugSubsection > > > toCodeViewSubsectionList(BumpPtrAllocator &Allocator, ArrayRef< YAMLDebugSubsection > Subsections, const codeview::StringsAndChecksums &SC)
LLVM_ABI ArrayRef< uint8_t > toDebugH(const DebugHSection &DebugH, BumpPtrAllocator &Alloc)
LLVM_ABI ArrayRef< uint8_t > toDebugT(ArrayRef< LeafRecord >, BumpPtrAllocator &Alloc, StringRef SectionName)
detail::packed_endian_specific_integral< uint32_t, llvm::endianness::little, unaligned > ulittle32_t
detail::packed_endian_specific_integral< uint32_t, llvm::endianness::little, aligned > aligned_ulittle32_t
llvm::function_ref< void(const Twine &Msg)> ErrorHandler
LLVM_ABI bool yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH, uint64_t MaxSize)
This is an optimization pass for GlobalISel generic memory operations.
std::string utostr(uint64_t X, bool isNeg=false)
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
OutputIt copy(R &&Range, OutputIt Out)
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
void consumeError(Error Err)
Consume a Error without doing anything.
std::optional< PEHeader > OptionalHeader
std::vector< Section > Sections
std::vector< Symbol > Symbols
std::optional< object::coff_load_configuration64 > LoadConfig64
std::optional< object::coff_load_configuration32 > LoadConfig32
LLVM_ABI void writeAsBinary(yaml::ContiguousBlobAccumulator &CBA) const
std::optional< uint32_t > UInt32
LLVM_ABI size_t size() const
std::vector< CodeViewYAML::YAMLDebugSubsection > DebugS
std::vector< SectionDataEntry > StructuredData
std::optional< std::vector< BBAddrMapYAML::BBAddrMapEntry > > BBAddrMapEntries
std::vector< CodeViewYAML::LeafRecord > DebugT
yaml::BinaryRef SectionData
std::optional< CodeViewYAML::DebugHSection > DebugH
std::vector< CodeViewYAML::LeafRecord > DebugP
std::optional< std::vector< BBAddrMapYAML::PGOAnalysisMapEntry > > PGOAnalyses
std::vector< Relocation > Relocations
std::optional< COFF::AuxiliaryWeakExternal > WeakExternal
std::optional< COFF::AuxiliarybfAndefSymbol > bfAndefSymbol
COFF::SymbolComplexType ComplexType
std::optional< COFF::AuxiliarySectionDefinition > SectionDefinition
std::optional< COFF::AuxiliaryFunctionDefinition > FunctionDefinition
COFF::SymbolBaseType SimpleType
std::optional< COFF::AuxiliaryCLRToken > CLRToken
uint32_t PointerToRelocations
uint16_t NumberOfLineNumbers
uint32_t PointerToRawData
uint16_t NumberOfRelocations
uint32_t PointerToLineNumbers
uint8_t NumberOfAuxSymbols
Common declarations for yaml2obj.