diff --git a/llvm/include/llvm/ObjectYAML/XCOFFYAML.h b/llvm/include/llvm/ObjectYAML/XCOFFYAML.h --- a/llvm/include/llvm/ObjectYAML/XCOFFYAML.h +++ b/llvm/include/llvm/ObjectYAML/XCOFFYAML.h @@ -59,10 +59,19 @@ uint8_t NumberOfAuxEntries; }; +struct StringTable { + Optional ContentSize; // The total size of the string table. + Optional Length; // The value of the length field for the first + // 4 bytes of the table. + Optional> Strings; + Optional RawContent; +}; + struct Object { FileHeader Header; std::vector
Sections; std::vector Symbols; + StringTable StrTbl; Object(); }; } // namespace XCOFFYAML @@ -100,6 +109,10 @@ static void mapping(IO &IO, XCOFFYAML::Section &Sec); }; +template <> struct MappingTraits { + static void mapping(IO &IO, XCOFFYAML::StringTable &Str); +}; + template <> struct MappingTraits { static void mapping(IO &IO, XCOFFYAML::Object &Obj); }; diff --git a/llvm/lib/ObjectYAML/XCOFFEmitter.cpp b/llvm/lib/ObjectYAML/XCOFFEmitter.cpp --- a/llvm/lib/ObjectYAML/XCOFFEmitter.cpp +++ b/llvm/lib/ObjectYAML/XCOFFEmitter.cpp @@ -18,8 +18,9 @@ #include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Support/EndianStream.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -33,7 +34,7 @@ public: XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH) : Obj(Obj), W(OS, support::big), ErrHandler(EH), - Strings(StringTableBuilder::XCOFF) { + StrTblBuilder(StringTableBuilder::XCOFF) { Is64Bit = Obj.Header.Magic == (llvm::yaml::Hex16)XCOFF::XCOFF64; } bool writeXCOFF(); @@ -43,18 +44,20 @@ bool initFileHeader(uint64_t CurrentOffset); bool initSectionHeader(uint64_t &CurrentOffset); bool initRelocations(uint64_t &CurrentOffset); + bool initStringTable(); bool assignAddressesAndIndices(); void writeFileHeader(); void writeSectionHeader(); bool writeSectionData(); bool writeRelocations(); bool writeSymbols(); + void writeStringTable(); XCOFFYAML::Object &Obj; bool Is64Bit = false; support::endian::Writer W; yaml::ErrorHandler ErrHandler; - StringTableBuilder Strings; + StringTableBuilder StrTblBuilder; uint64_t StartOffset; // Map the section name to its corrresponding section index. DenseMap SectionIndexMap = { @@ -140,20 +143,79 @@ return initRelocations(CurrentOffset); } +bool XCOFFWriter::initStringTable() { + if (Obj.StrTbl.RawContent) { + size_t RawSize = Obj.StrTbl.RawContent->binary_size(); + if (Obj.StrTbl.Strings || Obj.StrTbl.Length) { + ErrHandler( + "can't specify Strings or Length when RawContent is specified"); + return false; + } + if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < RawSize) { + ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + + ") is less than the RawContent data size (" + Twine(RawSize) + + ")"); + return false; + } + return true; + } + if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize <= 3) { + ErrHandler("ContentSize shouldn't be less than 4 without RawContent"); + return false; + } + + // Build the string table. + StrTblBuilder.clear(); + + if (Obj.StrTbl.Strings) { + // All specified strings should be added to the string table. + for (StringRef StringEnt : *Obj.StrTbl.Strings) + StrTblBuilder.add(StringEnt); + + size_t StrTblIdx = 0; + size_t NumOfStrings = Obj.StrTbl.Strings->size(); + for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { + if (nameShouldBeInStringTable(YamlSym.SymbolName)) { + if (StrTblIdx < NumOfStrings) { + // Overwrite the symbol name with the specified string. + YamlSym.SymbolName = (*Obj.StrTbl.Strings)[StrTblIdx]; + ++StrTblIdx; + } else + // Names that are not overwritten are still stored in the string + // table. + StrTblBuilder.add(YamlSym.SymbolName); + } + } + } else { + for (XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { + if (nameShouldBeInStringTable(YamlSym.SymbolName)) + StrTblBuilder.add(YamlSym.SymbolName); + } + } + + StrTblBuilder.finalize(); + + size_t StrTblSize = StrTblBuilder.getSize(); + if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize < StrTblSize) { + ErrHandler("specified ContentSize (" + Twine(*Obj.StrTbl.ContentSize) + + ") is less than the size of the data that would otherwise be " + "written (" + + Twine(StrTblSize) + ")"); + return false; + } + + return true; +} + bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) { // The default format of the object file is XCOFF32. InitFileHdr.Magic = XCOFF::XCOFF32; InitFileHdr.NumberOfSections = Obj.Sections.size(); InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size(); - for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { + for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) // Add the number of auxiliary symbols to the total number. InitFileHdr.NumberOfSymTableEntries += YamlSym.NumberOfAuxEntries; - if (nameShouldBeInStringTable(YamlSym.SymbolName)) - Strings.add(YamlSym.SymbolName); - } - // Finalize the string table. - Strings.finalize(); // Calculate SymbolTableOffset for the file header. if (InitFileHdr.NumberOfSymTableEntries) { @@ -171,7 +233,6 @@ } bool XCOFFWriter::assignAddressesAndIndices() { - Strings.clear(); uint64_t FileHdrSize = Is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32; uint64_t SecHdrSize = @@ -182,8 +243,13 @@ // Calculate section header info. if (!initSectionHeader(CurrentOffset)) return false; + // Calculate file header info. - return initFileHeader(CurrentOffset); + if (!initFileHeader(CurrentOffset)) + return false; + + // Initialize the string table. + return initStringTable(); } void XCOFFWriter::writeFileHeader() { @@ -309,13 +375,13 @@ for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { if (Is64Bit) { W.write(YamlSym.Value); - W.write(Strings.getOffset(YamlSym.SymbolName)); + W.write(StrTblBuilder.getOffset(YamlSym.SymbolName)); } else { if (nameShouldBeInStringTable(YamlSym.SymbolName)) { // For XCOFF32: A value of 0 indicates that the symbol name is in the // string table. W.write(0); - W.write(Strings.getOffset(YamlSym.SymbolName)); + W.write(StrTblBuilder.getOffset(YamlSym.SymbolName)); } else { writeName(YamlSym.SymbolName, W); } @@ -340,6 +406,41 @@ return true; } +void XCOFFWriter::writeStringTable() { + if (Obj.StrTbl.RawContent) { + Obj.StrTbl.RawContent->writeAsBinary(W.OS); + if (Obj.StrTbl.ContentSize && + *Obj.StrTbl.ContentSize > Obj.StrTbl.RawContent->binary_size()) + W.OS.write_zeros(*Obj.StrTbl.ContentSize - + Obj.StrTbl.RawContent->binary_size()); + return; + } + + size_t StrTblBuilderSize = StrTblBuilder.getSize(); + // Write the string table directly if no length value is specified. + if (!Obj.StrTbl.Length && !Obj.StrTbl.ContentSize) { + if (StrTblBuilderSize <= 4) + return; + StrTblBuilder.write(W.OS); + return; + } + + // Serialize the string table's content to a temporary buffer. + std::unique_ptr Buf = + WritableMemoryBuffer::getNewMemBuffer(StrTblBuilderSize); + uint8_t *Ptr = reinterpret_cast(Buf->getBufferStart()); + StrTblBuilder.write(Ptr); + // Replace the first 4 bytes with the specified length value. + memset(Ptr, 0, 4); + support::endian::write32be(Ptr, Obj.StrTbl.Length ? *Obj.StrTbl.Length + : *Obj.StrTbl.ContentSize); + // Copy the buffer content to the actual output stream. + W.OS.write(Buf->getBufferStart(), Buf->getBufferSize()); + // Add zeros as padding after strings. + if (Obj.StrTbl.ContentSize && *Obj.StrTbl.ContentSize > StrTblBuilderSize) + W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize); +} + bool XCOFFWriter::writeXCOFF() { if (!assignAddressesAndIndices()) return false; @@ -354,9 +455,7 @@ } if (!Obj.Symbols.empty() && !writeSymbols()) return false; - // Write the string table. - if (Strings.getSize() > 4) - Strings.write(W.OS); + writeStringTable(); return true; } diff --git a/llvm/lib/ObjectYAML/XCOFFYAML.cpp b/llvm/lib/ObjectYAML/XCOFFYAML.cpp --- a/llvm/lib/ObjectYAML/XCOFFYAML.cpp +++ b/llvm/lib/ObjectYAML/XCOFFYAML.cpp @@ -143,7 +143,7 @@ } void MappingTraits::mapping(IO &IO, XCOFFYAML::Symbol &S) { - IO.mapRequired("Name", S.SymbolName); + IO.mapOptional("Name", S.SymbolName); IO.mapOptional("Value", S.Value); IO.mapOptional("Section", S.SectionName); IO.mapOptional("Type", S.Type); @@ -151,11 +151,19 @@ IO.mapOptional("NumberOfAuxEntries", S.NumberOfAuxEntries); } +void MappingTraits::mapping(IO &IO, XCOFFYAML::StringTable &Str) { + IO.mapOptional("ContentSize", Str.ContentSize); + IO.mapOptional("Length", Str.Length); + IO.mapOptional("Strings", Str.Strings); + IO.mapOptional("RawContent", Str.RawContent); +} + void MappingTraits::mapping(IO &IO, XCOFFYAML::Object &Obj) { IO.mapTag("!XCOFF", true); IO.mapRequired("FileHeader", Obj.Header); IO.mapOptional("Sections", Obj.Sections); IO.mapOptional("Symbols", Obj.Symbols); + IO.mapOptional("StringTable", Obj.StrTbl); } } // namespace yaml diff --git a/llvm/test/tools/obj2yaml/XCOFF/aix.yaml b/llvm/test/tools/obj2yaml/XCOFF/aix.yaml --- a/llvm/test/tools/obj2yaml/XCOFF/aix.yaml +++ b/llvm/test/tools/obj2yaml/XCOFF/aix.yaml @@ -77,4 +77,4 @@ # CHECK-NEXT: Type: 0x0 # CHECK-NEXT: StorageClass: C_HIDEXT # CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: ... +## TODO: Dump the string table. diff --git a/llvm/test/tools/yaml2obj/XCOFF/string-table.yaml b/llvm/test/tools/yaml2obj/XCOFF/string-table.yaml --- a/llvm/test/tools/yaml2obj/XCOFF/string-table.yaml +++ b/llvm/test/tools/yaml2obj/XCOFF/string-table.yaml @@ -0,0 +1,296 @@ +## Check that yaml2obj is able to customize the string table. +## `ContentSize`, `Length`, `Strings` and/or `RawContent` can be specified in +## YAML. Here we test the behaviour in various cases. + +## Case 1: yaml2obj writes the default content (i.e. long symbol names in +## XCOFF32 or any symbol names in XCOFF64) when no StringTable field +## is specified. +# RUN: yaml2obj --docnum=1 %s -DSYMNAME='nameInStrTbl' -o %t1 +# RUN: llvm-readobj %t1 --string-table | FileCheck %s --check-prefix=CASE1 + +# CASE1: StringTable { +# CASE1-NEXT: Length: 17 +# CASE1-NEXT: [ 4] nameInStrTbl +# CASE1-NEXT: } + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Symbols: + - Name: [[SYMNAME=]] + - Name: [[SYMNAME2=]] +StringTable: + ContentSize: [[CONTENTSIZE=]] + Length: [[LENGTHVALUE=]] + RawContent: [[RAWCONTENT=]] + +## We can specify `ContentSize` only when the value is equal to or greater +## than the content size. For greater cases, zeros are added as padding. +## Case 2-4 are trying to check this. + +## Case 2: produce a string table with a specified `ContentSize`. In this case, +## there is no default content and the content is filled with zeroes. +# RUN: yaml2obj --docnum=1 %s -DCONTENTSIZE=20 -o %t2 +# RUN: llvm-readobj %t2 -s --string-table | FileCheck %s --check-prefix=CASE2 + +# CASE2: StringTable { +# CASE2-NEXT: Length: 20 +# CASE2-NEXT: } + +## Case 3: if the value of `ContentSize` is greater than the content size, +## yaml2obj adds zeros as padding after the default content. +# RUN: yaml2obj --docnum=1 %s -DSYMNAME='nameInStrTbl' -DCONTENTSIZE=20 -o %t3 +# RUN: llvm-readobj %t3 --string-table | FileCheck %s --check-prefix=CASE3 + +# CASE3: StringTable { +# CASE3-NEXT: Length: 20 +# CASE3-NEXT: [ 4] nameInStrTbl +# CASE3-NEXT: } + +## Case 4: an error is reported when the value of "ContentSize" is less than +## the content size. +# RUN: not yaml2obj --docnum=1 %s -DSYMNAME='nameInStrTbl' -DCONTENTSIZE=10 \ +# RUN: -o %t4 2>&1 | FileCheck %s --check-prefix=CASE4 + +# CASE4: yaml2obj: error: specified ContentSize (10) is less than the size of the data that would otherwise be written (17) + +## We can specify `Strings` for a string table. Default contents (ie. symbol +## names in string table) will be overwritten by specified values. Case 5-7 +## are trying to check this function. Notice that we do not specify `ContentSize` +## in those cases, and the length value is implicitly generated. + +## Case 5: produce a string table with specified `Strings` directly. In this +## case, there is no default content. +# RUN: yaml2obj --docnum=2 %s -o %t5 +# RUN: llvm-readobj %t5 --string-table | FileCheck %s --check-prefix=CASE5 + +# CASE5: StringTable { +# CASE5-NEXT: Length: 8 +# CASE5-NEXT: [ 4] b +# CASE5-NEXT: [ 6] a +# CASE5-NEXT: } + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Symbols: + - Name: [[SYMNAME=]] + - Name: [[SYMNAME2=]] + - Name: [[SYMNAME3=]] +StringTable: + ContentSize: [[CONTENTSIZE=]] + Length: [[LENGTHVALUE=]] + RawContent: [[RAWCONTENT=]] + Strings: + - a + - b + +## Case 6: if the number of `Strings` is greater than default strings, all +## default strings will be overwritten by specified ones. +# RUN: yaml2obj --docnum=2 %s -DSYMNAME='nameInStrTbl' -o %t6 +# RUN: llvm-readobj %t6 -s --string-table | FileCheck %s --check-prefix=CASE6 + +# CASE6: Symbols [ +# CASE6-NEXT: Symbol { +# CASE6-NEXT: Index: 0 +# CASE6-NEXT: Name: a +# CASE6-NEXT: Value: 0x0 +# CASE6-NEXT: Section: N_UNDEF +# CASE6-NEXT: Type: 0x0 +# CASE6-NEXT: StorageClass: C_NULL (0x0) +# CASE6-NEXT: NumberOfAuxEntries: 0 +# CASE6-NEXT: } +# CASE6-NEXT: Symbol { +# CASE6-NEXT: Index: 1 +# CASE6-NEXT: Name: +# CASE6-NEXT: Value: 0x0 +# CASE6-NEXT: Section: N_UNDEF +# CASE6-NEXT: Type: 0x0 +# CASE6-NEXT: StorageClass: C_NULL (0x0) +# CASE6-NEXT: NumberOfAuxEntries: 0 +# CASE6-NEXT: } +# CASE6-NEXT: Symbol { +# CASE6-NEXT: Index: 2 +# CASE6-NEXT: Name: +# CASE6-NEXT: Value: 0x0 +# CASE6-NEXT: Section: N_UNDEF +# CASE6-NEXT: Type: 0x0 +# CASE6-NEXT: StorageClass: C_NULL (0x0) +# CASE6-NEXT: NumberOfAuxEntries: 0 +# CASE6-NEXT: } +# CASE6-NEXT: ] +# CASE6-NEXT: StringTable { +# CASE6-NEXT: Length: 8 +# CASE6-NEXT: [ 4] b +# CASE6-NEXT: [ 6] a +# CASE6-NEXT: } + +## Case 7: if the number of `Strings` is less than default strings, default +## strings will be partially overwritten by specified ones, and the +## unoverwritten strings will still be stored after specified strings +## in the string table. +# RUN: yaml2obj --docnum=2 %s -DSYMNAME='nameInStrTbl' \ +# RUN: -DSYMNAME2='name2InStrTbl' -DSYMNAME3='name3InStrTbl' -o %t7 +# RUN: llvm-readobj %t7 -s --string-table | FileCheck %s --check-prefix=CASE7 + +# CASE7: Symbols [ +# CASE7-NEXT: Symbol { +# CASE7-NEXT: Index: 0 +# CASE7-NEXT: Name: a +# CASE7-NEXT: Value: 0x0 +# CASE7-NEXT: Section: N_UNDEF +# CASE7-NEXT: Type: 0x0 +# CASE7-NEXT: StorageClass: C_NULL (0x0) +# CASE7-NEXT: NumberOfAuxEntries: 0 +# CASE7-NEXT: } +# CASE7-NEXT: Symbol { +# CASE7-NEXT: Index: 1 +# CASE7-NEXT: Name: b +# CASE7-NEXT: Value: 0x0 +# CASE7-NEXT: Section: N_UNDEF +# CASE7-NEXT: Type: 0x0 +# CASE7-NEXT: StorageClass: C_NULL (0x0) +# CASE7-NEXT: NumberOfAuxEntries: 0 +# CASE7-NEXT: } +# CASE7-NEXT: Symbol { +# CASE7-NEXT: Index: 2 +# CASE7-NEXT: Name: name3InStrTbl +# CASE7-NEXT: Value: 0x0 +# CASE7-NEXT: Section: N_UNDEF +# CASE7-NEXT: Type: 0x0 +# CASE7-NEXT: StorageClass: C_NULL (0x0) +# CASE7-NEXT: NumberOfAuxEntries: 0 +# CASE7-NEXT: } +# CASE7-NEXT: ] +# CASE7-NEXT: StringTable { +# CASE7-NEXT: Length: 22 +# CASE7-NEXT: [ 4] name3InStrTbl +# CASE7-NEXT: [ 12] b +# CASE7-NEXT: [ 14] a +# CASE7-NEXT: } + +## We can specify both `ContentSize` and `Strings` when the length value is equal +## to or greater than the content size. Case 8-11 are trying to check this. + +## Case 8: produce a string table with specified `ContentSize` and `Strings` when +## the value is greater than the size of specified strings. In this case, +## there is no default content. +# RUN: yaml2obj --docnum=2 %s -DCONTENTSIZE=20 -o %t8 +# RUN: llvm-readobj %t8 --string-table | FileCheck %s --check-prefix=CASE8 + +# CASE8: StringTable { +# CASE8-NEXT: Length: 20 +# CASE8-NEXT: [ 4] b +# CASE8-NEXT: [ 6] a +# CASE8-NEXT: } + +## Case 9: for a string table with default contents, we can specify +## `ContentSize` and `Strings` when the length size is greater than the +## the data that would otherwise be written. +# RUN: yaml2obj --docnum=2 %s -DCONTENTSIZE=30 -DSYMNAME='nameInStrTbl' \ +# RUN: -DSYMNAME2='name2InStrTbl' -DSYMNAME3='name3InStrTbl' -o %t9 +# RUN: llvm-readobj %t9 --string-table | FileCheck %s --check-prefix=CASE9 + +# CASE9: StringTable { +# CASE9-NEXT: Length: 30 +# CASE9-NEXT: [ 4] name3InStrTbl +# CASE9-NEXT: [ 12] b +# CASE9-NEXT: [ 14] a +# CASE9-NEXT: } + +## Case 10: an error is reported when the value of `ContentSize` is less than the +## final content size. None of `ContentSize`, `Strings` or default +## contents is empty in this case. +# RUN: not yaml2obj --docnum=2 %s -DCONTENTSIZE=10 -DSYMNAME='nameInStrTbl' \ +# RUN: -DSYMNAME2='name2InStrTbl' -DSYMNAME3='name3InStrTbl' -o %t10 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CASE10 + +# CASE10: yaml2obj: error: specified ContentSize (10) is less than the size of the data that would otherwise be written (22) + +## We can use `RawContent` to generate a string table. Case 11-15 are trying to +## check the `RawContent`. + +## Case 11: if `RawContent` is specified and no `ContentSize` is specified. Write the +## `RawContent` data. +# RUN: yaml2obj --docnum=1 %s -DRAWCONTENT="000000090062006300" -o %t11 +# RUN: llvm-readobj %t11 --string-table | FileCheck %s --check-prefix=CASE11 + +# CASE11: StringTable { +# CASE11-NEXT: Length: 9 +# CASE11-NEXT: [ 5] b +# CASE11-NEXT: [ 7] c +# CASE11-NEXT: } + +## Case 12: if `RawContent` is specified and `ContentSize` matches the size of the +## `RawContent` data. Write the `RawContent` data. +# RUN: yaml2obj --docnum=1 %s -DRAWCONTENT="000000090062006300" -DCONTENTSIZE=9 -o %t12 +# RUN: llvm-readobj %t12 --string-table | FileCheck %s --check-prefix=CASE12 + +# CASE12: StringTable { +# CASE12-NEXT: Length: 9 +# CASE12-NEXT: [ 5] b +# CASE12-NEXT: [ 7] c +# CASE12-NEXT: } + +## Case 13: an error is reported when `ContentSize` is less than the `RawContent` +## `RawContent` data size. +# RUN: not yaml2obj --docnum=1 %s -DRAWCONTENT="000000090062006300" -DCONTENTSIZE=6 \ +# RUN: -o %t13 2>&1 | FileCheck %s --check-prefix=CASE13 + +# CASE13: yaml2obj: error: specified ContentSize (6) is less than the RawContent data size (9) + +## Case 14: if `RawContent` is specified and `ContentSize` is greater than the +## `RawContent` data size. Pad the RawContent with trailing zeroes. +# RUN: yaml2obj --docnum=1 %s -DRAWCONTENT="000000090062006300" -DCONTENTSIZE=11 -o %t14 +# RUN: llvm-readobj %t14 --string-table | FileCheck %s --check-prefix=CASE14 + +# CASE14: StringTable { +# CASE14-NEXT: Length: 9 +# CASE14-NEXT: [ 5] b +# CASE14-NEXT: [ 7] c +# CASE14-NEXT: } + +## Case 15: report an error when the string table is not null terminated. +# RUN: yaml2obj --docnum=1 %s -DRAWCONTENT="000000090062000063" -o %t15 +# RUN: not llvm-readobj -s 2>&1 %t15 | FileCheck -DFILE=%t15 %s --check-prefix=CASE15 + +# CASE15: llvm-readobj: error: '[[FILE]]': String table must end with a null terminator + +## We can specify `Length`. Use the value of the `Length` field for the first 4 bytes +## of the table. The value may not make sense for the data that is being written. +## Case 16-18 are trying to check this. + +## Case 16: report an error if the `Length` is specified as well as `RawContent`. +# RUN: not yaml2obj --docnum=1 %s -DRAWCONTENT="0062006300" -DLENGTHVALUE=9 \ +# RUN: -o %t16 2>&1 | FileCheck %s --check-prefix=CASE16 + +# CASE16: yaml2obj: error: can't specify Strings or Length when RawContent is specified + +## Case 17: use the value of the `Length` field for the first 4 bytes of the table. +# RUN: yaml2obj --docnum=1 %s -DSYMNAME='nameInStrTbl' -DSYMNAME2='name2InStrTbl' \ +# RUN: -DLENGTHVALUE=17 -o %t17 +# RUN: llvm-readobj --string-table %t17 | FileCheck %s --check-prefix=CASE17 + +# CASE17: StringTable { +# CASE17-NEXT: Length: 17 +# CASE17-NEXT: [ 4] nameInStrTbl +# CASE17-NEXT: } + +## Case 18: an error will be triggered in llvm-readobj if `Length` value is invalid +## for a string table. +# RUN: yaml2obj --docnum=1 %s -DSYMNAME='nameInStrTbl' -DLENGTHVALUE=20 -o %t18 +# RUN: not llvm-readobj -s 2>&1 %t18 | FileCheck -DFILE=%t18 %s --check-prefix=CASE18 + +# CASE18: llvm-readobj: error: '[[FILE]]': The end of the file was unexpectedly encountered + +## Case 19: report an error if both `RawContent` and `Strings` are specified. +# RUN: not yaml2obj --docnum=2 %s -DRAWCONTENT="0062006300" -o %t19 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CASE19 + +# CASE19: yaml2obj: error: can't specify Strings or Length when RawContent is specified + +## Case 20: report an error if `ContentSize` is less than 4 without `RawContent`. +# RUN: not yaml2obj --docnum=1 %s -DCONTENTSIZE=3 -o %t20 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CASE20 + +# CASE20: yaml2obj: error: ContentSize shouldn't be less than 4 without RawContent