diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -188,7 +188,10 @@ } StringRef XCOFFObjectFile::getStringTable() const { - return StringRef(StringTable.Data, StringTable.Size); + // If the size is less than or equal to 4, then the string table contains no + // string data. + return StringRef(StringTable.Data, + StringTable.Size <= 4 ? 0 : StringTable.Size); } Expected diff --git a/llvm/test/tools/llvm-readobj/XCOFF/string-table.yaml b/llvm/test/tools/llvm-readobj/XCOFF/string-table.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/XCOFF/string-table.yaml @@ -0,0 +1,42 @@ +## Test that the string table is dumped correctly. + +## The string table contains more than one entry. +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readobj --string-table %t1 | FileCheck %s --check-prefix=BASIC + +# BASIC: StringTable { +# BASIC-NEXT: [ 4] name2 +# BASIC-NEXT: [ a] name1 +# BASIC-NEXT: } + +--- !XCOFF +FileHeader: + MagicNumber: 0x01F7 +Symbols: + - Name: name1 + - Name: name2 + +## The string table just contains a single-byte sized string entry. +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readobj --string-table %t2 | FileCheck %s --check-prefix=SINGLE-BYTE + +# SINGLE-BYTE: StringTable { +# SINGLE-BYTE-NEXT: [ 4] n +# SINGLE-BYTE-NEXT: } + +--- !XCOFF +FileHeader: + MagicNumber: 0x01F7 +Symbols: + - Name: n + +## There is no string table. +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: llvm-readobj --string-table %t3 | FileCheck %s --check-prefix=NO-STRTBL + +# NO-STRTBL: StringTable { +# NO-STRTBL-NEXT: } + +--- !XCOFF +FileHeader: + MagicNumber: 0x01F7 diff --git a/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml b/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml --- a/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml +++ b/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: llvm-readobj --headers --symbols %t | \ +# RUN: llvm-readobj --headers --symbols --string-table %t | \ # RUN: FileCheck %s --check-prefix=CHECK64 --- !XCOFF @@ -134,3 +134,9 @@ # CHECK64-NEXT: NumberOfAuxEntries: 0 # CHECK64-NEXT: } # CHECK64-NEXT: ] +# CHECK64-NEXT: StringTable { +# CHECK64-NEXT: [ 4] .text +# CHECK64-NEXT: [ a] .abs +# CHECK64-NEXT: [ f] .undef +# CHECK64-NEXT: [ 16] .file +# CHECK64-NEXT: } diff --git a/llvm/test/tools/yaml2obj/XCOFF/long-symbol-name.yaml b/llvm/test/tools/yaml2obj/XCOFF/long-symbol-name.yaml --- a/llvm/test/tools/yaml2obj/XCOFF/long-symbol-name.yaml +++ b/llvm/test/tools/yaml2obj/XCOFF/long-symbol-name.yaml @@ -2,8 +2,6 @@ # RUN: yaml2obj %s -o %t # RUN: llvm-readobj --symbols --string-table %t | FileCheck %s -## FIXME: The first item of StringTable should be `[ 4] .longname`. - # CHECK: AddressSize: 32bit # CHECK-NEXT: Symbols [ # CHECK-NEXT: Symbol { @@ -26,7 +24,7 @@ # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: StringTable { -# CHECK-NEXT: [ 3] ..longname +# CHECK-NEXT: [ 4] .longname # CHECK-NEXT: } --- !XCOFF diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -110,7 +110,7 @@ virtual void printStackMap() const = 0; - void printAsStringList(StringRef StringContent); + void printAsStringList(StringRef StringContent, size_t StringDataOffset = 0); void printSectionsAsString(const object::ObjectFile &Obj, ArrayRef Sections); diff --git a/llvm/tools/llvm-readobj/ObjDumper.cpp b/llvm/tools/llvm-readobj/ObjDumper.cpp --- a/llvm/tools/llvm-readobj/ObjDumper.cpp +++ b/llvm/tools/llvm-readobj/ObjDumper.cpp @@ -52,9 +52,13 @@ W << (isPrint(Start[i]) ? static_cast(Start[i]) : '.'); } -void ObjDumper::printAsStringList(StringRef StringContent) { +void ObjDumper::printAsStringList(StringRef StringContent, + size_t StringDataOffset) { const uint8_t *StrContent = StringContent.bytes_begin(); - const uint8_t *CurrentWord = StrContent; + // Some formats contain additional metadata at the start which should not be + // interpreted as strings. Skip these bytes, but account for them in the + // string offsets. + const uint8_t *CurrentWord = StrContent + StringDataOffset; const uint8_t *StrEnd = StringContent.bytes_end(); while (CurrentWord <= StrEnd) { diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp --- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -460,7 +460,9 @@ void XCOFFDumper::printStringTable() { DictScope DS(W, "StringTable"); StringRef StrTable = Obj.getStringTable(); - printAsStringList(StrTable); + // Print strings from the fifth byte, since the first four bytes contain the + // length (in bytes) of the string table (including the length field). + printAsStringList(StrTable, 4); } void XCOFFDumper::printDynamicSymbols() {