diff --git a/llvm/docs/CommandGuide/llvm-nm.rst b/llvm/docs/CommandGuide/llvm-nm.rst --- a/llvm/docs/CommandGuide/llvm-nm.rst +++ b/llvm/docs/CommandGuide/llvm-nm.rst @@ -126,6 +126,20 @@ Use BSD output format. Alias for ``--format=bsd``. +.. option:: -X + + Specify the type of XCOFF object file, ELF object file, IR object file input + from command line or from big archive files that llvm-nm should examine. The + mode must be one of the following: + 32 + Processes only 32-bit object files. + 64 + Processes only 64-bit object files. + 32_64 + Processes both 32-bit and 64-bit object files. + any + Processes all of the supported object files. + .. option:: --debug-syms, -a Show all symbols, even those usually suppressed. diff --git a/llvm/test/tools/llvm-nm/XCOFF/option-X.test b/llvm/test/tools/llvm-nm/XCOFF/option-X.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/XCOFF/option-X.test @@ -0,0 +1,85 @@ +## Test the option "-X" of llvm-nm for xcoff object file. +## The option specifies the type of object file llvm-nm should examine. + +# RUN: yaml2obj --docnum=1 %s -o %t32_xcoff.o +# RUN: yaml2obj --docnum=2 %s -o %t64_xcoff.o +# RUN: rm -rf %t.a +# RUN: llvm-ar -q -c %t.a %t32_xcoff.o %t64_xcoff.o + +# RUN: llvm-nm -X32 %t32_xcoff.o | FileCheck --check-prefixes=BIT32 %s --implicit-check-not={{.}} +# RUN: llvm-nm -X32 %t.a | FileCheck --check-prefixes=BIT32,ARC32 %s +# BIT32: 00000000 D var32 +# ARC32-NOT: 0000000000000000 D var64 + +# RUN: llvm-nm -X64 %t64_xcoff.o | FileCheck --check-prefixes=BIT64 %s --implicit-check-not={{.}} +# RUN: llvm-nm -X64 %t.a | FileCheck --check-prefixes=BIT64,ARC64 %s +# ARC64-NOT: 00000000 D var32 +# BIT64: 0000000000000000 D var64 + +# RUN: llvm-nm %t32_xcoff.o %t64_xcoff.o | FileCheck --check-prefixes=BOTH %s -DFILE32=%t32_xcoff.o -DFILE64=%t64_xcoff.o --match-full-lines +# RUN: llvm-nm -X32_64 %t32_xcoff.o %t64_xcoff.o | FileCheck --check-prefixes=BOTH %s -DFILE32=%t32_xcoff.o -DFILE64=%t64_xcoff.o --match-full-lines +# RUN: llvm-nm -Xany %t32_xcoff.o %t64_xcoff.o | FileCheck --check-prefixes=BOTH %s -DFILE32=%t32_xcoff.o -DFILE64=%t64_xcoff.o --match-full-lines + +# BOTH: [[FILE32]]: +# BOTH-NEXT: 00000000 D var32 +# BOTH-EMPTY: +# BOTH-NEXT: [[FILE64]]: +# BOTH-NEXT: 0000000000000000 D var64 + +# RUN: llvm-nm %t.a | FileCheck --check-prefixes=ARCHIVE --match-full-lines %s +# RUN: llvm-nm -X32_64 %t.a | FileCheck --check-prefixes=ARCHIVE --match-full-lines %s +# RUN: llvm-nm -Xany %t.a | FileCheck --check-prefixes=ARCHIVE --match-full-lines %s + +# ARCHIVE: 00000000 D var32 +# ARCHIVE: 0000000000000000 D var64 + +# RUN: llvm-nm -X64 %t32_xcoff.o | count 0 +# RUN: llvm-nm -X32 %t64_xcoff.o | count 0 + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF + Flags: 0x0002 +AuxiliaryHeader: + Magic: 0x10B + Version: 0x2 + TextSectionSize: 0x280 + DataSectionSize: 0x90 +Sections: + - Name: .text + Flags: [ STYP_TEXT ] + - Name: .data + Flags: [ STYP_DATA ] +Symbols: + - Name: var32 + Section: .data + Type: 0x4000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW + +--- !XCOFF +FileHeader: + MagicNumber: 0x1F7 + Flags: 0x0002 +AuxiliaryHeader: + Magic: 0x10B + Version: 0x2 + TextSectionSize: 0x280 + DataSectionSize: 0x90 +Sections: + - Name: .text + Flags: [ STYP_TEXT ] + - Name: .data + Flags: [ STYP_DATA ] +Symbols: + - Name: var64 + Section: .data + Type: 0x3000 + StorageClass: C_EXT + AuxEntries: + - Type: AUX_CSECT + SymbolAlignmentAndType: 0x09 + StorageMappingClass: XMC_RW diff --git a/llvm/test/tools/llvm-nm/option-X-elf-bitcode.test b/llvm/test/tools/llvm-nm/option-X-elf-bitcode.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-nm/option-X-elf-bitcode.test @@ -0,0 +1,89 @@ +## Test the option "-X" of llvm-nm for bitcode and elf object file. + +# RUN: echo "target triple = \"powerpcle-unknown-linux-gnu\"" > %t32.ll +# RUN: echo "@C32 = dso_local global i32 5, align 4" >> %t32.ll +# RUN: echo "@undef_var32 = external dso_local global i32, align 4" >> %t32.ll +# RUN: echo "define dso_local i32 @foo32(i32 %i) {" >> %t32.ll +# RUN: echo "entry:" >> %t32.ll +# RUN: echo " %i.addr = alloca i32, align 4" >> %t32.ll +# RUN: echo " store i32 %i, i32* %i.addr, align 4" >> %t32.ll +# RUN: echo " %0 = load i32, i32* %i.addr, align 4" >> %t32.ll +# RUN: echo " %1 = load i32, i32* @undef_var32, align 4" >> %t32.ll +# RUN: echo " %add = add nsw i32 %0, %1" >> %t32.ll +# RUN: echo " ret i32 %add" >> %t32.ll +# RUN: echo "}" >> %t32.ll + +# RUN: echo "target triple = \"powerpc64le-unknown-linux-gnu\"" > %t64.ll +# RUN: echo "@C64 = dso_local global i32 5, align 4" >> %t64.ll +# RUN: echo "@static_var64 = internal global i32 2, align 4" >> %t64.ll +# RUN: echo "define dso_local signext i32 @bar64() {" >> %t64.ll +# RUN: echo "entry:" >> %t64.ll +# RUN: echo " %0 = load i32, i32* @static_var64, align 4" >> %t64.ll +# RUN: echo " %1 = load i32, i32* @C64, align 4" >> %t64.ll +# RUN: echo " %add = add nsw i32 %0, %1" >> %t64.ll +# RUN: echo " ret i32 %add" >> %t64.ll +# RUN: echo "}" >> %t64.ll + +# RUN: llvm-as -o %t32.bc %t32.ll +# RUN: llvm-as -o %t64.bc %t64.ll + +# RUN: llvm-nm --format=just-symbols -X32 %t32.bc %t64.bc | FileCheck %s -DFILE1=%t32.bc --check-prefixes=BITCODE32 --implicit-check-not={{.}} +# RUN: llvm-nm --format=just-symbols -X64 %t32.bc %t64.bc | FileCheck %s -DFILE2=%t64.bc --check-prefixes=BITCODE64 --implicit-check-not={{.}} +# RUN: llvm-nm --format=just-symbols %t32.bc %t64.bc | FileCheck %s -DFILE1=%t32.bc -DFILE2=%t64.bc --check-prefixes=BITCODE32,BITCODE64 +# RUN: llvm-nm --format=just-symbols -X32_64 %t32.bc %t64.bc | FileCheck %s -DFILE1=%t32.bc -DFILE2=%t64.bc --check-prefixes=BITCODE32,BITCODE64 +# RUN: llvm-nm --format=just-symbols -Xany %t32.bc %t64.bc | FileCheck %s -DFILE1=%t32.bc -DFILE2=%t64.bc --check-prefixes=BITCODE32,BITCODE64 + +# BITCODE32: [[FILE1]]: +# BITCODE32-NEXT: C32 +# BITCODE32-NEXT: foo32 +# BITCODE32-NEXT: undef_var32 + +# BITCODE64: [[FILE2]]: +# BITCODE64-NEXT: C64 +# BITCODE64-NEXT: bar64 +# BITCODE64-NEXT: static_var64 + +# RUN: yaml2obj --docnum=1 %s -o %t_elf32.o +# RUN: yaml2obj --docnum=2 %s -o %t_elf64.o + +# RUN: llvm-nm --format=just-symbols -X32 %t_elf32.o %t_elf64.o | FileCheck %s -DFILE32=%t_elf32.o --check-prefixes=ELF32 --implicit-check-not={{.}} +# RUN: llvm-nm --format=just-symbols -X64 %t_elf32.o %t_elf64.o | FileCheck %s -DFILE64=%t_elf64.o --check-prefixes=ELF64 --implicit-check-not={{.}} +# RUN: llvm-nm --format=just-symbols %t_elf32.o %t_elf64.o | FileCheck %s -DFILE32=%t_elf32.o -DFILE64=%t_elf64.o --check-prefixes=ELF32,ELF64 +# RUN: llvm-nm --format=just-symbols -X32_64 %t_elf32.o %t_elf64.o | FileCheck %s -DFILE32=%t_elf32.o -DFILE64=%t_elf64.o --check-prefixes=ELF32,ELF64 +# RUN: llvm-nm --format=just-symbols -Xany %t_elf32.o %t_elf64.o | FileCheck %s -DFILE32=%t_elf32.o -DFILE64=%t_elf64.o --check-prefixes=ELF32,ELF64 + +# ELF32: [[FILE32]]: +# ELF32-NEXT: global_data_symbol32 + +# ELF64: [[FILE64]]: +# ELF64-NEXT: global_data_symbol64 + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: + - Name: .data + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_WRITE] +Symbols: + - Name: global_data_symbol32 + Binding: STB_GLOBAL + Section: .data + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_AARCH64 +Sections: + - Name: .data + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_WRITE] +Symbols: + - Name: global_data_symbol64 + Binding: STB_GLOBAL + Section: .data diff --git a/llvm/tools/llvm-nm/Opts.td b/llvm/tools/llvm-nm/Opts.td --- a/llvm/tools/llvm-nm/Opts.td +++ b/llvm/tools/llvm-nm/Opts.td @@ -13,6 +13,7 @@ def : Separate<["--"], name>, Alias(NAME #_EQ)>; } +def X : JoinedOrSeparate<["-"], "X">, HelpText<"Specifies the type of object file to examine. The value must be one of : 32, 64 ,32_64 ,any (default)">; def debug_syms : FF<"debug-syms", "Show all symbols, even debugger only">; def defined_only : FF<"defined-only", "Show only defined symbols">; defm demangle : BB<"demangle", "Demangle C++ symbol names", "Don't demangle symbol names">; 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 @@ -84,9 +84,11 @@ }; enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols }; +enum class BitModeTy { Bit32, Bit64, Bit32_64, Any }; } // namespace static bool ArchiveMap; +static BitModeTy BitMode; static bool DebugSyms; static bool DefinedOnly; static bool Demangle; @@ -1807,9 +1809,22 @@ } } +static bool shouldDump(SymbolicFile &Obj) { + // -X option only work for XCOFF object file, ELF object file, IR object file + // input from command line or archive files. + if (!isa(Obj) && !isa(Obj) && + !isa(Obj)) + return true; + + return isSymbolList64Bit(Obj) ? BitMode != BitModeTy::Bit32 + : BitMode != BitModeTy::Bit64; +} + static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, StringRef ArchiveName = {}, StringRef ArchitectureName = {}) { + if (!shouldDump(Obj)) + return; auto Symbols = Obj.symbols(); std::vector SymbolVersions; if (DynamicSyms) { @@ -2025,7 +2040,7 @@ } if (!checkMachOAndArchFlags(O, Filename)) return; - if (!PrintFileName && !ExportSymbols) { + if (!PrintFileName && !ExportSymbols && shouldDump(*O)) { outs() << "\n"; if (isa(O)) { outs() << Filename << "(" << O->getFileName() << ")"; @@ -2377,6 +2392,18 @@ NoDyldInfo = Args.hasArg(OPT_no_dyldinfo); // XCOFF specific options. + StringRef Mode = Args.getLastArgValue(OPT_X, "any"); + if (Mode == "32") + BitMode = BitModeTy::Bit32; + else if (Mode == "64") + BitMode = BitModeTy::Bit64; + else if (Mode == "32_64") + BitMode = BitModeTy::Bit32_64; + else if (Mode == "any") + BitMode = BitModeTy::Any; + else + error("--X value should be one of: 32, 64,32_64, (default) any"); + NoRsrc = Args.hasArg(OPT_no_rsrc); // llvm-nm only reads binary files.