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,48 @@ return true; } +void XCOFFWriter::writeStringTable() { + if (Obj.StrTbl.RawContent) { + Obj.StrTbl.RawContent->writeAsBinary(W.OS); + if (Obj.StrTbl.ContentSize) { + assert(*Obj.StrTbl.ContentSize >= Obj.StrTbl.RawContent->binary_size() && + "Specified ContentSize is less than the RawContent size."); + W.OS.write_zeros(*Obj.StrTbl.ContentSize - + Obj.StrTbl.RawContent->binary_size()); + } + return; + } + + size_t StrTblBuilderSize = StrTblBuilder.getSize(); + // If neither Length nor ContentSize is specified, write the StrTblBuilder + // directly, which contains the auto-generated Length value. + 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, which contain the auto-generated Length value, + // with the specified 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) { + assert(*Obj.StrTbl.ContentSize >= StrTblBuilderSize && + "Specified ContentSize is less than the StringTableBuilder size."); + W.OS.write_zeros(*Obj.StrTbl.ContentSize - StrTblBuilderSize); + } +} + bool XCOFFWriter::writeXCOFF() { if (!assignAddressesAndIndices()) return false; @@ -354,9 +462,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 new file mode 100644 --- /dev/null +++ b/llvm/test/tools/yaml2obj/XCOFF/string-table.yaml @@ -0,0 +1,291 @@ +## 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. +## Cases 2-6 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: the value of `ContentSize` matches the actual content size. +# RUN: yaml2obj --docnum=1 %s -DSYMNAME='nameInStrTbl' -DCONTENTSIZE=17 -o %t4 +# RUN: llvm-readobj %t4 --string-table | FileCheck %s --check-prefix=CASE4 + +# CASE4: StringTable { +# CASE4-NEXT: Length: 17 +# CASE4-NEXT: [ 4] nameInStrTbl +# CASE4-NEXT: } + +## Case 5: an error is reported when the value of "ContentSize" is less than +## the content size. +# RUN: not yaml2obj --docnum=1 %s -DSYMNAME='nameInStrTbl' -DCONTENTSIZE=16 \ +# RUN: -o %t5 2>&1 | FileCheck %s --check-prefix=CASE5 + +# CASE5: error: specified ContentSize (16) is less than the size of the data that would otherwise be written (17) + +## Case 6: an error is reported when `ContentSize` is less than 4 without +## `RawContent`. +# RUN: not yaml2obj --docnum=1 %s -DCONTENTSIZE=3 -o %t6 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CASE6 + +# CASE6: error: ContentSize shouldn't be less than 4 without RawContent + +## We can specify `Strings` for a string table. Default contents (ie. symbol +## names in string table) will be overwritten by specified values. Cases 7-9 +## are trying to check this function. + +## Case 7: produce a string table with specified `Strings` directly. In this +## case, there is no default content. +# RUN: yaml2obj --docnum=2 %s -o %t7 +# RUN: llvm-readobj %t7 --string-table | FileCheck %s --check-prefix=CASE7 + +# CASE7: StringTable { +# CASE7-NEXT: Length: 8 +# CASE7-NEXT: [ 4] b +# CASE7-NEXT: [ 6] a +# CASE7-NEXT: } + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Symbols: + - Name: [[SYMNAME=]] + - Name: [[SYMNAME2=]] + - Name: [[SYMNAME3=]] +StringTable: + ContentSize: [[CONTENTSIZE=]] + Length: [[LENGTHVALUE=]] + RawContent: [[RAWCONTENT=]] + Strings: + - a + - b + +## Case 8: if the number of `Strings` is greater than or equal to the number +## of default strings, all default strings will be overwritten by +## specified ones. +# RUN: yaml2obj --docnum=2 %s -DSYMNAME='nameInStrTbl' -o %t8 +# RUN: llvm-readobj %t8 -s --string-table | FileCheck %s --check-prefix=CASE8 + +# CASE8: Symbols [ +# CASE8-NEXT: Symbol { +# CASE8-NEXT: Index: 0 +# CASE8-NEXT: Name: a +# CASE8-NEXT: Value: 0x0 +# CASE8-NEXT: Section: N_UNDEF +# CASE8-NEXT: Type: 0x0 +# CASE8-NEXT: StorageClass: C_NULL (0x0) +# CASE8-NEXT: NumberOfAuxEntries: 0 +# CASE8-NEXT: } +# CASE8-NEXT: Symbol { +# CASE8-NEXT: Index: 1 +# CASE8-NEXT: Name: +# CASE8-NEXT: Value: 0x0 +# CASE8-NEXT: Section: N_UNDEF +# CASE8-NEXT: Type: 0x0 +# CASE8-NEXT: StorageClass: C_NULL (0x0) +# CASE8-NEXT: NumberOfAuxEntries: 0 +# CASE8-NEXT: } +# CASE8-NEXT: Symbol { +# CASE8-NEXT: Index: 2 +# CASE8-NEXT: Name: +# CASE8-NEXT: Value: 0x0 +# CASE8-NEXT: Section: N_UNDEF +# CASE8-NEXT: Type: 0x0 +# CASE8-NEXT: StorageClass: C_NULL (0x0) +# CASE8-NEXT: NumberOfAuxEntries: 0 +# CASE8-NEXT: } +# CASE8-NEXT: ] +# CASE8-NEXT: StringTable { +# CASE8-NEXT: Length: 8 +# CASE8-NEXT: [ 4] b +# CASE8-NEXT: [ 6] a +# CASE8-NEXT: } + +## Case 9: if the number of `Strings` is less than the number of default +## strings, default strings will be partially overwritten. The +## remaining strings will still be stored after the specified strings +## in the string table. +# RUN: yaml2obj --docnum=2 %s -DSYMNAME='nameInStrTbl' \ +# RUN: -DSYMNAME2='name2InStrTbl' -DSYMNAME3='name3InStrTbl' -o %t9 +# RUN: llvm-readobj %t9 -s --string-table | FileCheck %s --check-prefix=CASE9 + +# CASE9: Symbols [ +# CASE9-NEXT: Symbol { +# CASE9-NEXT: Index: 0 +# CASE9-NEXT: Name: a +# CASE9-NEXT: Value: 0x0 +# CASE9-NEXT: Section: N_UNDEF +# CASE9-NEXT: Type: 0x0 +# CASE9-NEXT: StorageClass: C_NULL (0x0) +# CASE9-NEXT: NumberOfAuxEntries: 0 +# CASE9-NEXT: } +# CASE9-NEXT: Symbol { +# CASE9-NEXT: Index: 1 +# CASE9-NEXT: Name: b +# CASE9-NEXT: Value: 0x0 +# CASE9-NEXT: Section: N_UNDEF +# CASE9-NEXT: Type: 0x0 +# CASE9-NEXT: StorageClass: C_NULL (0x0) +# CASE9-NEXT: NumberOfAuxEntries: 0 +# CASE9-NEXT: } +# CASE9-NEXT: Symbol { +# CASE9-NEXT: Index: 2 +# CASE9-NEXT: Name: name3InStrTbl +# CASE9-NEXT: Value: 0x0 +# CASE9-NEXT: Section: N_UNDEF +# CASE9-NEXT: Type: 0x0 +# CASE9-NEXT: StorageClass: C_NULL (0x0) +# CASE9-NEXT: NumberOfAuxEntries: 0 +# CASE9-NEXT: } +# CASE9-NEXT: ] +# CASE9-NEXT: StringTable { +# CASE9-NEXT: Length: 22 +# CASE9-NEXT: [ 4] name3InStrTbl +# CASE9-NEXT: [ 12] b +# CASE9-NEXT: [ 14] a +# CASE9-NEXT: } + +## We can specify both `ContentSize` and `Strings` when `ContentSize` is equal +## to or greater than the content size. Cases 10-12 are trying to check this. + +## Case 10: 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 %t10 +# RUN: llvm-readobj %t10 --string-table | FileCheck %s --check-prefix=CASE10 + +# CASE10: StringTable { +# CASE10-NEXT: Length: 20 +# CASE10-NEXT: [ 4] b +# CASE10-NEXT: [ 6] a +# CASE10-NEXT: } + +## Case 11: for a string table with default contents, we can specify +## `ContentSize` and `Strings` when the `ContentSize` is greater +## than the data that would otherwise be written. +# RUN: yaml2obj --docnum=2 %s -DCONTENTSIZE=30 -DSYMNAME='nameInStrTbl' \ +# RUN: -DSYMNAME2='name2InStrTbl' -DSYMNAME3='name3InStrTbl' -o %t11 +# RUN: llvm-readobj %t11 --string-table | FileCheck %s --check-prefix=CASE11 + +# CASE11: StringTable { +# CASE11-NEXT: Length: 30 +# CASE11-NEXT: [ 4] name3InStrTbl +# CASE11-NEXT: [ 12] b +# CASE11-NEXT: [ 14] a +# CASE11-NEXT: } + +## Case 12: 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 %t12 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CASE12 + +# CASE12: 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. Cases 13-16 are trying to +## check the `RawContent`. + +## Case 13: if `RawContent` is specified and no `ContentSize` is specified. +## Write the `RawContent` data. +# RUN: yaml2obj --docnum=1 %s -DRAWCONTENT="000000090062006300" -o %t13 +# RUN: llvm-readobj %t13 --string-table | FileCheck %s --check-prefix=CASE13 + +# CASE13: StringTable { +# CASE13-NEXT: Length: 9 +# CASE13-NEXT: [ 5] b +# CASE13-NEXT: [ 7] c +# CASE13-NEXT: } + +## Case 14: 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 %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: an error is reported when `ContentSize` is less than the `RawContent` +## data size. +# RUN: not yaml2obj --docnum=1 %s -DRAWCONTENT="000000090062006300" -DCONTENTSIZE=6 \ +# RUN: -o %t15 2>&1 | FileCheck %s --check-prefix=CASE15 + +# CASE15: error: specified ContentSize (6) is less than the RawContent data size (9) + +## Case 16: 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 %t16 +# RUN: llvm-readobj %t16 --string-table | FileCheck %s --check-prefix=CASE16 + +# CASE16: StringTable { +# CASE16-NEXT: Length: 9 +# CASE16-NEXT: [ 5] b +# CASE16-NEXT: [ 7] c +# CASE16-NEXT: } + +## 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. Cases 17-20 are trying to check this. + +## Case 17: report an error if the `Length` is specified as well as `RawContent`. +# RUN: not yaml2obj --docnum=1 %s -DRAWCONTENT="0062006300" -DLENGTHVALUE=9 \ +# RUN: -o %t17 2>&1 | FileCheck %s --check-prefix=CASE17 + +# CASE17: error: can't specify Strings or Length when RawContent is specified + +## Case 18: report an error if both `RawContent` and `Strings` are specified. +# RUN: not yaml2obj --docnum=2 %s -DRAWCONTENT="0062006300" -o %t18 2>&1 \ +# RUN: | FileCheck %s --check-prefix=CASE18 + +# CASE18: error: can't specify Strings or Length when RawContent is specified + +## Case 19: use the value of the `Length` field for the first 4 bytes of the +## table. We dump the string table from the offset of 0x38. +# RUN: yaml2obj --docnum=1 %s -DSYMNAME='nameInStrTbl' -DLENGTHVALUE=20 -o %t19 +# RUN: od -A n -t x1 -v -j 0x38 %t19 | FileCheck %s --check-prefix=CASE19 + +# CASE19: 00 00 00 14 6e 61 6d 65 49 6e 53 74 72 54 62 6c +# CASE19-NEXT: 00