diff --git a/llvm/test/tools/llvm-nm/XCOFF/basic.test b/llvm/test/tools/llvm-nm/XCOFF/basic.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/XCOFF/basic.test @@ -0,0 +1,118 @@ +## Test llvm-nm for XCOFF object files. + +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-nm %t.o | FileCheck --match-full-lines %s + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Sections: + - Name: .text + Address: 0x0 + Flags: [ STYP_TEXT ] + - Name: .data + Flags: [ STYP_DATA ] + - Name: .bss + Flags: [ STYP_BSS ] + - Name: .debug + Flags: [ STYP_DEBUG ] + - Name: .except + Flags: [ STYP_EXCEPT ] +Symbols: + - Name: .file + Section: N_DEBUG + StorageClass: C_FILE + - Name: .text + Value: 0x10 + Section: .text + StorageClass: C_STAT + NumberOfAuxEntries: 1 + - Name: .data + Value: 0x80 + Section: .data + StorageClass: C_STAT + NumberOfAuxEntries: 1 + - Name: .bss + Value: 0x310 + Section: .bss + StorageClass: C_STAT + - Name: .debug + Section: .debug + StorageClass: C_STAT + - Name: ._ZL5func0v + Section: .text + StorageClass: C_EXT + Type: 0x20 + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x02 + StorageMappingClass: XMC_PR + - Name: ._Z3fwpv + Section: .text + StorageClass: C_WEAKEXT + Type: 0x20 + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x02 + StorageMappingClass: XMC_PR + - Name: val + Section: .data + StorageClass: C_EXT + Type: 0x20 + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x01 + StorageMappingClass: XMC_RW + SectionOrLength: 0x4 + - Name: extval + Section: N_UNDEF + StorageClass: C_EXT + Type: 0x00 + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x01 + StorageMappingClass: XMC_UA + SectionOrLength: 0x0 + - Name: comval + Section: .bss + Value: 0x13C + StorageClass: C_EXT + Type: 0x00 + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x03 + StorageMappingClass: XMC_RW + SectionOrLength: 0x0 + - Name: abs + Section: N_ABS + - Name: symIn_N_debug + Section: N_DEBUG + - Name: .except + Section: .except + +## Global weak symbol. +# CHECK: 00000000 W ._Z3fwpv +## Global symbol in .text section. +# CHECK-NEXT: 00000000 T ._ZL5func0v +## Symbol in .bss section. +# CHECK-NEXT: 00000310 b .bss +## Local symbol in .data section. +# CHECK-NEXT: 00000080 d .data +## Symbol in .debug section. +# CHECK-NEXT: 00000000 N .debug +## Symbol in .except section. +# CHECK-NEXT: 00000000 ? .except +## Symbol .file. +# CHECK-NEXT: 00000000 f .file +## Local symbol in .text section. +# CHECK-NEXT: 00000010 t .text +## Absolute symbol. +# CHECK-NEXT: 00000000 a abs +## Common symbol. +# CHECK-NEXT: 0000013c C comval +## Undefined symbol. +# CHECK-NEXT: U extval +## Symbol in N_DEBUG section. +# CHECK-NEXT: 00000000 ? symIn_N_debug +## Global symbol in .data section. +# CHECK-NEXT: 00000000 D val diff --git a/llvm/test/tools/llvm-nm/XCOFF/basic_64.test b/llvm/test/tools/llvm-nm/XCOFF/basic_64.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/XCOFF/basic_64.test @@ -0,0 +1,20 @@ +## Test showing 8 byte addresses for llvm-nm for XCOFF 64-bit object files. + +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-nm %t.o | FileCheck --match-full-lines %s + +--- !XCOFF +FileHeader: + MagicNumber: 0x1F7 +Sections: + - Name: .text + Address: 0x0 + Flags: [ STYP_TEXT ] +Symbols: + - Name: .text + Value: 0x10 + Section: .text + StorageClass: C_STAT + NumberOfAuxEntries: 1 + +# CHECK: 0000000000000010 t .text diff --git a/llvm/test/tools/llvm-nm/XCOFF/invalid-section-index.test b/llvm/test/tools/llvm-nm/XCOFF/invalid-section-index.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/XCOFF/invalid-section-index.test @@ -0,0 +1,20 @@ +## Test the behavior of the symbol reference section. + +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-nm %t.o 2>&1 | FileCheck %s -DFILE=%t.o + +# CHECK: llvm-nm{{(\.exe)?}}: warning: [[FILE]]: for symbol with index 0: the section index (4) is invalid +# CHECK-NEXT: 00000000 ? .text + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Sections: + - Name: .text +Symbols: + - Name: .text + Value: 0x0 + SectionIndex: 4 + Type: 0x0 + StorageClass: C_STAT + NumberOfAuxEntries: 1 diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp --- a/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/llvm/tools/llvm-nm/llvm-nm.cpp @@ -31,6 +31,7 @@ #include "llvm/Object/TapiFile.h" #include "llvm/Object/TapiUniversal.h" #include "llvm/Object/Wasm.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" @@ -127,6 +128,20 @@ static StringRef ToolName; +static void warn(Error Err, Twine FileName, Twine Context = Twine()) { + assert(Err); + + // Flush the standard output so that the warning isn't interleaved with other + // output if stdout and stderr are writing to the same place. + outs().flush(); + + handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { + WithColor::warning(errs(), ToolName) + << FileName << ": " << (Context.str().empty() ? "" : Context + ": ") + << EI.message() << "\n"; + }); +} + static void error(Twine Message, Twine Path = Twine()) { HadError = true; WithColor::error(errs(), ToolName) << Path << ": " << Message << "\n"; @@ -246,6 +261,9 @@ return Triple(IRObj->getTargetTriple()).isArch64Bit(); if (isa(Obj) || isa(Obj)) return false; + if (XCOFFObjectFile *XCOFFObj = dyn_cast(&Obj)) + return XCOFFObj->is64Bit(); + if (isa(Obj)) return false; if (TapiFile *Tapi = dyn_cast(&Obj)) @@ -897,6 +915,42 @@ return '?'; } +static char getSymbolNMTypeChar(XCOFFObjectFile &Obj, symbol_iterator I) { + Expected TypeOrErr = I->getType(); + if (!TypeOrErr) { + warn(TypeOrErr.takeError(), Obj.getFileName(), + "for symbol with index " + + Twine(Obj.getSymbolIndex(I->getRawDataRefImpl().p))); + return '?'; + } + + uint32_t SymType = *TypeOrErr; + + if (SymType == SymbolRef::ST_File) + return 'f'; + + // If the I->getSection() call would return an error, the earlier I->getType() + // call will already have returned the same error first. + section_iterator SecIter = cantFail(I->getSection()); + + if (SecIter == Obj.section_end()) + return '?'; + + if (Obj.isDebugSection(SecIter->getRawDataRefImpl())) + return 'N'; + + if (SecIter->isText()) + return 't'; + + if (SecIter->isData()) + return 'd'; + + if (SecIter->isBSS()) + return 'b'; + + return '?'; +} + static char getSymbolNMTypeChar(COFFImportFile &Obj) { switch (Obj.getCOFFImportHeader()->getType()) { case COFF::IMPORT_CODE: @@ -1045,6 +1099,8 @@ Ret = getSymbolNMTypeChar(*IR, I); else if (COFFObjectFile *COFF = dyn_cast(&Obj)) Ret = getSymbolNMTypeChar(*COFF, I); + else if (XCOFFObjectFile *XCOFF = dyn_cast(&Obj)) + Ret = getSymbolNMTypeChar(*XCOFF, I); else if (COFFImportFile *COFFImport = dyn_cast(&Obj)) Ret = getSymbolNMTypeChar(*COFFImport); else if (MachOObjectFile *MachO = dyn_cast(&Obj))