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 @@ -1,80 +1,147 @@ -# RUN: obj2yaml %S/Inputs/aix_xcoff.o | FileCheck %s -# Test that we can parse the XCOFF object file correctly. -# CHECK: --- !XCOFF -# CHECK-NEXT: FileHeader: -# CHECK-NEXT: MagicNumber: 0x1DF -# CHECK-NEXT: NumberOfSections: 2 -# CHECK-NEXT: CreationTime: 1552337792 -# CHECK-NEXT: OffsetToSymbolTable: 0x13A -# CHECK-NEXT: EntriesInSymbolTable: 22 -# CHECK-NEXT: AuxiliaryHeaderSize: 0 -# CHECK-NEXT: Flags: 0x0 +## This is a basic test to check if we can parse the XCOFF object file correctly. +# RUN: yaml2obj %s -DMAGIC=0x01DF -o %t-32 +# RUN: obj2yaml %t-32 | FileCheck %s --check-prefix=CHECK32 +# RUN: yaml2obj %s -DMAGIC=0x01F7 -o %t-64 +# RUN: obj2yaml %t-64 | FileCheck %s --check-prefix=CHECK64 -# CHECK: Symbols: -# CHECK-NEXT: - Name: .file -# CHECK-NEXT: Value: 0x0 -# CHECK-NEXT: Section: N_DEBUG -# CHECK-NEXT: Type: 0x3 -# CHECK-NEXT: StorageClass: C_FILE -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: i -# CHECK-NEXT: Value: 0x0 -# CHECK-NEXT: Section: N_UNDEF -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_EXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: TestforXcoff -# CHECK-NEXT: Value: 0x0 -# CHECK-NEXT: Section: N_UNDEF -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_EXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: .text -# CHECK-NEXT: Value: 0x0 -# CHECK-NEXT: Section: .text -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_HIDEXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: .main -# CHECK-NEXT: Value: 0x0 -# CHECK-NEXT: Section: .text -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_EXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: main -# CHECK-NEXT: Value: 0x60 -# CHECK-NEXT: Section: .data -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_HIDEXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: main -# CHECK-NEXT: Value: 0x60 -# CHECK-NEXT: Section: .data -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_EXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: .data -# CHECK-NEXT: Value: 0x70 -# CHECK-NEXT: Section: .data -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_HIDEXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: TOC -# CHECK-NEXT: Value: 0x74 -# CHECK-NEXT: Section: .data -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_HIDEXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: i -# CHECK-NEXT: Value: 0x74 -# CHECK-NEXT: Section: .data -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_HIDEXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -# CHECK-NEXT: - Name: TestforXcoff -# CHECK-NEXT: Value: 0x78 -# CHECK-NEXT: Section: .data -# CHECK-NEXT: Type: 0x0 -# CHECK-NEXT: StorageClass: C_HIDEXT -# CHECK-NEXT: NumberOfAuxEntries: 1 -## TODO: Dump the string table. +# CHECK32: --- !XCOFF +# CHECK32-NEXT: FileHeader: +# CHECK32-NEXT: MagicNumber: 0x1DF +# CHECK32-NEXT: NumberOfSections: 2 +# CHECK32-NEXT: CreationTime: 0 +# CHECK32-NEXT: OffsetToSymbolTable: 0x80 +# CHECK32-NEXT: EntriesInSymbolTable: 4 +# CHECK32-NEXT: AuxiliaryHeaderSize: 0 +# CHECK32-NEXT: Flags: 0x0 +# CHECK32-NEXT: Sections: +# CHECK32-NEXT: - Name: .text +# CHECK32-NEXT: Address: 0x0 +# CHECK32-NEXT: Size: 0x4 +# CHECK32-NEXT: FileOffsetToData: 0x64 +# CHECK32-NEXT: FileOffsetToRelocations: 0x6C +# CHECK32-NEXT: FileOffsetToLineNumbers: 0x0 +# CHECK32-NEXT: NumberOfRelocations: 0x1 +# CHECK32-NEXT: NumberOfLineNumbers: 0x0 +# CHECK32-NEXT: Flags: [ STYP_TEXT ] +# CHECK32-NEXT: SectionData: '00007400' +# CHECK32-NEXT: Relocations: +# CHECK32-NEXT: - Address: 0xE +# CHECK32-NEXT: Symbol: 0x12 +# CHECK32-NEXT: Info: 0xF +# CHECK32-NEXT: Type: 0x3 +# CHECK32-NEXT: - Name: .data +# CHECK32-NEXT: Address: 0x4 +# CHECK32-NEXT: Size: 0x4 +# CHECK32-NEXT: FileOffsetToData: 0x68 +# CHECK32-NEXT: FileOffsetToRelocations: 0x76 +# CHECK32-NEXT: FileOffsetToLineNumbers: 0x0 +# CHECK32-NEXT: NumberOfRelocations: 0x1 +# CHECK32-NEXT: NumberOfLineNumbers: 0x0 +# CHECK32-NEXT: Flags: [ STYP_DATA ] +# CHECK32-NEXT: SectionData: '00007700' +# CHECK32-NEXT: Relocations: +# CHECK32-NEXT: - Address: 0x60 +# CHECK32-NEXT: Symbol: 0x8 +# CHECK32-NEXT: Info: 0x1F +# CHECK32-NEXT: Type: 0x0 +# CHECK32-NEXT: Symbols: +# CHECK32-NEXT: - Name: TestforXcoff +# CHECK32-NEXT: Value: 0x0 +# CHECK32-NEXT: Section: N_UNDEF +# CHECK32-NEXT: Type: 0x0 +# CHECK32-NEXT: StorageClass: C_EXT +# CHECK32-NEXT: NumberOfAuxEntries: 1 +# CHECK32-NEXT: - Name: .data +# CHECK32-NEXT: Value: 0x70 +# CHECK32-NEXT: Section: .data +# CHECK32-NEXT: Type: 0x0 +# CHECK32-NEXT: StorageClass: C_HIDEXT +# CHECK32-NEXT: NumberOfAuxEntries: 1 + +# CHECK64: --- !XCOFF +# CHECK64-NEXT: FileHeader: +# CHECK64-NEXT: MagicNumber: 0x1F7 +# CHECK64-NEXT: NumberOfSections: 2 +# CHECK64-NEXT: CreationTime: 0 +# CHECK64-NEXT: OffsetToSymbolTable: 0xCC +# CHECK64-NEXT: EntriesInSymbolTable: 4 +# CHECK64-NEXT: AuxiliaryHeaderSize: 0 +# CHECK64-NEXT: Flags: 0x0 +# CHECK64-NEXT: Sections: +# CHECK64-NEXT: - Name: .text +# CHECK64-NEXT: Address: 0x0 +# CHECK64-NEXT: Size: 0x4 +# CHECK64-NEXT: FileOffsetToData: 0xA8 +# CHECK64-NEXT: FileOffsetToRelocations: 0xB0 +# CHECK64-NEXT: FileOffsetToLineNumbers: 0x0 +# CHECK64-NEXT: NumberOfRelocations: 0x1 +# CHECK64-NEXT: NumberOfLineNumbers: 0x0 +# CHECK64-NEXT: Flags: [ STYP_TEXT ] +# CHECK64-NEXT: SectionData: '00007400' +# CHECK64-NEXT: Relocations: +# CHECK64-NEXT: - Address: 0xE +# CHECK64-NEXT: Symbol: 0x12 +# CHECK64-NEXT: Info: 0xF +# CHECK64-NEXT: Type: 0x3 +# CHECK64-NEXT: - Name: .data +# CHECK64-NEXT: Address: 0x4 +# CHECK64-NEXT: Size: 0x4 +# CHECK64-NEXT: FileOffsetToData: 0xAC +# CHECK64-NEXT: FileOffsetToRelocations: 0xBE +# CHECK64-NEXT: FileOffsetToLineNumbers: 0x0 +# CHECK64-NEXT: NumberOfRelocations: 0x1 +# CHECK64-NEXT: NumberOfLineNumbers: 0x0 +# CHECK64-NEXT: Flags: [ STYP_DATA ] +# CHECK64-NEXT: SectionData: '00007700' +# CHECK64-NEXT: Relocations: +# CHECK64-NEXT: - Address: 0x60 +# CHECK64-NEXT: Symbol: 0x8 +# CHECK64-NEXT: Info: 0x1F +# CHECK64-NEXT: Type: 0x0 +# CHECK64-NEXT: Symbols: +# CHECK64-NEXT: - Name: TestforXcoff +# CHECK64-NEXT: Value: 0x0 +# CHECK64-NEXT: Section: N_UNDEF +# CHECK64-NEXT: Type: 0x0 +# CHECK64-NEXT: StorageClass: C_EXT +# CHECK64-NEXT: NumberOfAuxEntries: 1 +# CHECK64-NEXT: - Name: .data +# CHECK64-NEXT: Value: 0x70 +# CHECK64-NEXT: Section: .data +# CHECK64-NEXT: Type: 0x0 +# CHECK64-NEXT: StorageClass: C_HIDEXT +# CHECK64-NEXT: NumberOfAuxEntries: 1 + +--- !XCOFF +FileHeader: + MagicNumber: [[MAGIC]] +Sections: + - Name: .text + Flags: [ STYP_TEXT ] + SectionData: '00007400' + Relocations: + - Address: 0xE + Symbol: 0x12 + Info: 0xF + Type: 0x3 + - Name: .data + Flags: [ STYP_DATA ] + SectionData: '00007700' + Relocations: + - Address: 0x60 + Symbol: 0x8 + Info: 0x1F + Type: 0x0 +Symbols: + - Name: TestforXcoff + Value: 0x0 + Section: N_UNDEF + Type: 0x0 + StorageClass: C_EXT + NumberOfAuxEntries: 1 + - Name: .data + Value: 0x70 + Section: .data + Type: 0x0 + StorageClass: C_HIDEXT + NumberOfAuxEntries: 1 diff --git a/llvm/test/tools/obj2yaml/XCOFF/invalid.yaml b/llvm/test/tools/obj2yaml/XCOFF/invalid.yaml --- a/llvm/test/tools/obj2yaml/XCOFF/invalid.yaml +++ b/llvm/test/tools/obj2yaml/XCOFF/invalid.yaml @@ -0,0 +1,34 @@ +## Test that obj2yaml reports a suitable error when it encounters invalid content. + +## Error1: failed to get section data. +# RUN: yaml2obj %s -DOFFSETTODATA=0x70 -o %t1 +# RUN: not obj2yaml %t1 2>&1 | FileCheck %s -DFILE=%t1 --check-prefix=ERROR1 + +# ERROR1: Error reading file: [[FILE]]: The end of the file was unexpectedly encountered + +--- !XCOFF +FileHeader: + MagicNumber: 0x01DF +Sections: + - Name: .text + Flags: [ STYP_TEXT ] + SectionData: '00007400' + FileOffsetToData: [[OFFSETTODATA=0x00]] +Symbols: + - Name: .longSymName + Value: 0x70 + Section: [[SYMSECNAME=".text"]] +StringTable: + Length: [[STRLENGTH=]] + +## Error2: failed to get the section name for a symbol. +# RUN: yaml2obj %s -DSYMSECNAME='.data' -o %t2 +# RUN: not obj2yaml %t2 2>&1 | FileCheck %s -DFILE=%t2 --check-prefix=ERROR2 + +# ERROR2: Error reading file: [[FILE]]: Invalid section index + +## Error3: failed to get the symbol name. +# RUN: yaml2obj %s -DSTRLENGTH=0 -o %t3 +# RUN: not obj2yaml %t3 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=ERROR3 + +# ERROR3: Error reading file: [[FILE]]: Invalid data was encountered while parsing the file diff --git a/llvm/tools/obj2yaml/xcoff2yaml.cpp b/llvm/tools/obj2yaml/xcoff2yaml.cpp --- a/llvm/tools/obj2yaml/xcoff2yaml.cpp +++ b/llvm/tools/obj2yaml/xcoff2yaml.cpp @@ -9,6 +9,7 @@ #include "obj2yaml.h" #include "llvm/Object/XCOFFObjectFile.h" #include "llvm/ObjectYAML/XCOFFYAML.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/YAMLTraits.h" using namespace llvm; @@ -19,38 +20,93 @@ const object::XCOFFObjectFile &Obj; XCOFFYAML::Object YAMLObj; void dumpHeader(); - std::error_code dumpSymbols(); + Error dumpSections(); + Error dumpSymbols(); + template + Error dumpSections(ArrayRef Sections); public: XCOFFDumper(const object::XCOFFObjectFile &obj) : Obj(obj) {} - std::error_code dump(); + Error dump(); XCOFFYAML::Object &getYAMLObj() { return YAMLObj; } }; } // namespace -std::error_code XCOFFDumper::dump() { +Error XCOFFDumper::dump() { dumpHeader(); + if (Error E = dumpSections()) + return E; return dumpSymbols(); } void XCOFFDumper::dumpHeader() { - YAMLObj.Header.Magic = Obj.getMagic(); YAMLObj.Header.NumberOfSections = Obj.getNumberOfSections(); YAMLObj.Header.TimeStamp = Obj.getTimeStamp(); - - // TODO FIXME only dump 32 bit header for now. - if (Obj.is64Bit()) - report_fatal_error("64-bit XCOFF files not supported yet."); - YAMLObj.Header.SymbolTableOffset = Obj.getSymbolTableOffset32(); - + YAMLObj.Header.SymbolTableOffset = Obj.is64Bit() + ? Obj.getSymbolTableOffset64() + : Obj.getSymbolTableOffset32(); YAMLObj.Header.NumberOfSymTableEntries = - Obj.getRawNumberOfSymbolTableEntries32(); + Obj.is64Bit() ? Obj.getNumberOfSymbolTableEntries64() + : Obj.getRawNumberOfSymbolTableEntries32(); YAMLObj.Header.AuxHeaderSize = Obj.getOptionalHeaderSize(); YAMLObj.Header.Flags = Obj.getFlags(); } -std::error_code XCOFFDumper::dumpSymbols() { +Error XCOFFDumper::dumpSections() { + if (Obj.is64Bit()) + return dumpSections( + Obj.sections64()); + return dumpSections( + Obj.sections32()); +} + +template +Error XCOFFDumper::dumpSections(ArrayRef Sections) { + std::vector &YamlSections = YAMLObj.Sections; + for (const Shdr &S : Sections) { + XCOFFYAML::Section YamlSec; + YamlSec.SectionName = S.getName(); + YamlSec.Address = S.PhysicalAddress; + YamlSec.Size = S.SectionSize; + YamlSec.NumberOfRelocations = S.NumberOfRelocations; + YamlSec.NumberOfLineNumbers = S.NumberOfLineNumbers; + YamlSec.FileOffsetToData = S.FileOffsetToRawData; + YamlSec.FileOffsetToRelocations = S.FileOffsetToRelocationInfo; + YamlSec.FileOffsetToLineNumbers = S.FileOffsetToLineNumberInfo; + YamlSec.Flags = S.Flags; + + // Dump section data. + if (S.FileOffsetToRawData) { + DataRefImpl SectionDRI; + SectionDRI.p = reinterpret_cast(&S); + Expected> SecDataRefOrErr = + Obj.getSectionContents(SectionDRI); + if (!SecDataRefOrErr) + return SecDataRefOrErr.takeError(); + YamlSec.SectionData = SecDataRefOrErr.get(); + } + + // Dump relocations. + if (S.NumberOfRelocations) { + auto RelRefOrErr = Obj.relocations(S); + if (!RelRefOrErr) + return RelRefOrErr.takeError(); + for (const Reloc &R : RelRefOrErr.get()) { + XCOFFYAML::Relocation YamlRel; + YamlRel.Type = R.Type; + YamlRel.Info = R.Info; + YamlRel.SymbolIndex = R.SymbolIndex; + YamlRel.VirtualAddress = R.VirtualAddress; + YamlSec.Relocations.push_back(YamlRel); + } + } + YamlSections.push_back(YamlSec); + } + return Error::success(); +} + +Error XCOFFDumper::dumpSymbols() { std::vector &Symbols = YAMLObj.Symbols; for (const SymbolRef &S : Obj.symbols()) { @@ -60,7 +116,7 @@ Expected SymNameRefOrErr = Obj.getSymbolName(SymbolDRI); if (!SymNameRefOrErr) { - return errorToErrorCode(SymNameRefOrErr.takeError()); + return SymNameRefOrErr.takeError(); } Sym.SymbolName = SymNameRefOrErr.get(); @@ -69,7 +125,7 @@ Expected SectionNameRefOrErr = Obj.getSymbolSectionName(SymbolEntRef); if (!SectionNameRefOrErr) - return errorToErrorCode(SectionNameRefOrErr.takeError()); + return SectionNameRefOrErr.takeError(); Sym.SectionName = SectionNameRefOrErr.get(); @@ -79,15 +135,15 @@ Symbols.push_back(Sym); } - return std::error_code(); + return Error::success(); } std::error_code xcoff2yaml(raw_ostream &Out, const object::XCOFFObjectFile &Obj) { XCOFFDumper Dumper(Obj); - if (std::error_code EC = Dumper.dump()) - return EC; + if (Error E = Dumper.dump()) + return errorToErrorCode(std::move(E)); yaml::Output Yout(Out); Yout << Dumper.getYAMLObj();