diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -355,6 +355,7 @@ Expected getSymbolName(DataRefImpl Symb) const override; Expected getSymbolAddress(DataRefImpl Symb) const override; uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; + uint32_t getSymbolAlignment(DataRefImpl Symb) const override; uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; Expected getSymbolType(DataRefImpl Symb) const override; Expected getSymbolSection(DataRefImpl Symb) const override; @@ -431,6 +432,11 @@ uint32_t getNumberOfSymbolTableEntries() const; uint32_t getSymbolIndex(uintptr_t SymEntPtr) const; + uint64_t getSymbolSize(DataRefImpl Symb) const; + uintptr_t getSymbolByIndex(uint32_t Idx) const { + return reinterpret_cast(SymbolTblPtr) + + XCOFF::SymbolTableEntrySize * Idx; + } uintptr_t getSymbolEntryAddressByIndex(uint32_t SymbolTableIndex) const; Expected getSymbolNameByIndex(uint32_t SymbolTableIndex) const; 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 @@ -220,15 +220,85 @@ return toSymbolRef(Symb).getValue(); } +uint32_t XCOFFObjectFile::getSymbolAlignment(DataRefImpl Symb) const { + uint64_t Result = 0; + XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); + if (XCOFFSym.isCsectSymbol()) { + Expected CsectAuxRefOrError = + XCOFFSym.getXCOFFCsectAuxRef(); + if (!CsectAuxRefOrError) + // TODO: report the error up the stack. + consumeError(CsectAuxRefOrError.takeError()); + else + Result = 1 << CsectAuxRefOrError.get().getAlignmentLog2(); + } + return Result; +} + uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { uint64_t Result = 0; - llvm_unreachable("Not yet implemented!"); + XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); + if (XCOFFSym.isCsectSymbol()) { + Expected CsectAuxRefOrError = + XCOFFSym.getXCOFFCsectAuxRef(); + if (!CsectAuxRefOrError) + // TODO: report the error up the stack. + consumeError(CsectAuxRefOrError.takeError()); + else { + XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get(); + assert(CsectAuxRef.getSymbolType() == XCOFF::XTY_CM); + Result = CsectAuxRef.getSectionOrLength(); + } + } return Result; } Expected XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const { - // TODO: Return the correct symbol type. + XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); + + if (XCOFFSym.isFunction()) + return SymbolRef::ST_Function; + + if (XCOFF::C_FILE == XCOFFSym.getStorageClass()) + return SymbolRef::ST_File; + + int16_t SecNum = XCOFFSym.getSectionNumber(); + if (SecNum <= 0) + return SymbolRef::ST_Other; + + Expected SecDRIOrErr = + getSectionByNum(XCOFFSym.getSectionNumber()); + + if (!SecDRIOrErr) + return SecDRIOrErr.takeError(); + + DataRefImpl SecDRI = SecDRIOrErr.get(); + + Expected SymNameOrError = XCOFFSym.getName(); + if (SymNameOrError) { + // The "TOC" symbol is treated as SymbolRef::ST_Other. + if (SymNameOrError.get() == "TOC") + return SymbolRef::ST_Other; + + // The symbol for a section name is treated as SymbolRef::ST_Other. + StringRef SecName; + if (is64Bit()) + SecName = XCOFFObjectFile::toSection64(SecDRIOrErr.get())->getName(); + else + SecName = XCOFFObjectFile::toSection32(SecDRIOrErr.get())->getName(); + + if (SecName == SymNameOrError.get()) + return SymbolRef::ST_Other; + } else + return SymNameOrError.takeError(); + + if (isSectionData(SecDRI) || isSectionBSS(SecDRI)) + return SymbolRef::ST_Data; + + if (isDebugSection(SecDRI)) + return SymbolRef::ST_Debug; + return SymbolRef::ST_Other; } @@ -500,8 +570,32 @@ } Expected XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { - uint32_t Result = 0; - // TODO: Return correct symbol flags. + XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); + uint32_t Result = SymbolRef::SF_None; + + if (XCOFFSym.getSectionNumber() == XCOFF::N_ABS) + Result |= SymbolRef::SF_Absolute; + + XCOFF::StorageClass SC = XCOFFSym.getStorageClass(); + if (XCOFF::C_EXT == SC || XCOFF::C_WEAKEXT == SC) + Result |= SymbolRef::SF_Global; + + if (XCOFF::C_WEAKEXT == SC) + Result |= SymbolRef::SF_Weak; + + if (XCOFFSym.isCsectSymbol()) { + Expected CsectAuxEntOrErr = + XCOFFSym.getXCOFFCsectAuxRef(); + if (CsectAuxEntOrErr) { + if (CsectAuxEntOrErr.get().getSymbolType() == XCOFF::XTY_CM) + Result |= SymbolRef::SF_Common; + } else + return CsectAuxEntOrErr.takeError(); + } + + if (XCOFFSym.getSectionNumber() == XCOFF::N_UNDEF) + Result |= SymbolRef::SF_Undefined; + return Result; } @@ -702,6 +796,25 @@ XCOFF::SymbolTableEntrySize; } +uint64_t XCOFFObjectFile::getSymbolSize(DataRefImpl Symb) const { + uint64_t Result = 0; + XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb); + if (XCOFFSym.isCsectSymbol()) { + Expected CsectAuxRefOrError = + XCOFFSym.getXCOFFCsectAuxRef(); + if (!CsectAuxRefOrError) + // TODO: report the error up the stack. + consumeError(CsectAuxRefOrError.takeError()); + else { + XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get(); + uint8_t SymType = CsectAuxRef.getSymbolType(); + if (SymType == XCOFF::XTY_SD || SymType == XCOFF::XTY_CM) + Result = CsectAuxRef.getSectionOrLength(); + } + } + return Result; +} + uintptr_t XCOFFObjectFile::getSymbolEntryAddressByIndex(uint32_t Index) const { return getAdvancedSymbolEntryAddress( reinterpret_cast(getPointerToSymbolTable()), Index); diff --git a/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test b/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test --- a/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test +++ b/llvm/test/tools/llvm-objdump/XCOFF/print-linenumber.test @@ -18,7 +18,7 @@ # LINES32: Inputs/basic32.o: file format aixcoff-rs6000 # LINES32: Disassembly of section .text: # LINES32: 00000000 <.text>: -# LINES32: ; main(): +# LINES32: ; .main(): # LINES32-NEXT: ; /basic.c:1 # LINES32-NEXT: 0: 38 60 00 00 li 3, 0 # LINES32-NEXT: ; /basic.c:3 @@ -35,7 +35,7 @@ # LINES64: Inputs/basic64.o: file format aix5coff64-rs6000 # LINES64: Disassembly of section .text: # LINES64: 0000000000000000 <.main>: -# LINES64: ; main(): +# LINES64: ; .main(): # LINES64-NEXT: ; /basic.c:1 # LINES64-NEXT: 0: 38 60 00 00 li 3, 0 # LINES64-NEXT: ; /basic.c:3 diff --git a/llvm/test/tools/llvm-objdump/XCOFF/symbol-table.test b/llvm/test/tools/llvm-objdump/XCOFF/symbol-table.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/XCOFF/symbol-table.test @@ -0,0 +1,110 @@ +; Test the --syms option for xcoff object files. +; Also test the --symbol-description option for xcoff object files, when specified with --syms. +; RUN: llc -mtriple powerpc-ibm-aix -mcpu=pwr4 -filetype=obj -o %t.o < %s +; RUN: llvm-objdump --syms %t.o | FileCheck --check-prefix=SYM %s +; RUN: llvm-objdump --syms --symbol-description %t.o | FileCheck --check-prefix=SYM-DES %s + +;; The IR below is generated by the following source code. +;; bash> cat test.c +;; const char* con= "Test for --symbols"; +;; int i; +;; char c ; +;; char *ap; +;; float f; +;; long long ll; +;; static int si; +;; extern int ei; +;; int bar(const char *v) { +;; si = 1; +;; return (int)v[0] + (int)v[2] + si + ei; +;; } +;; +;; void foo() { +;; bar(con); +;; } +;; +;; __attribute__ ((weak)) int wi=2; + + +@.str = private unnamed_addr constant [19 x i8] c"Test for --symbols\00", align 1 +@con = global i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str, i32 0, i32 0), align 4 +@si = internal global i32 0, align 4 +@ei = external global i32, align 4 +@wi = weak global i32 2, align 4 +@i = global i32 0, align 4 +@c = global i8 0, align 1 +@ap = global i8* null, align 4 +@f = global float 0.000000e+00, align 4 +@ll = global i64 0, align 8 + +define i32 @bar(i8* %v) { +entry: + %v.addr = alloca i8*, align 4 + store i8* %v, i8** %v.addr, align 4 + store i32 1, i32* @si, align 4 + %0 = load i8*, i8** %v.addr, align 4 + %arrayidx = getelementptr inbounds i8, i8* %0, i32 0 + %1 = load i8, i8* %arrayidx, align 1 + %conv = zext i8 %1 to i32 + %2 = load i8*, i8** %v.addr, align 4 + %arrayidx1 = getelementptr inbounds i8, i8* %2, i32 2 + %3 = load i8, i8* %arrayidx1, align 1 + %conv2 = zext i8 %3 to i32 + %add = add nsw i32 %conv, %conv2 + %4 = load i32, i32* @si, align 4 + %add3 = add nsw i32 %add, %4 + %5 = load i32, i32* @ei, align 4 + %add4 = add nsw i32 %add3, %5 + ret i32 %add4 +} + +define void @foo() { +entry: + %0 = load i8*, i8** @con, align 4 + %call = call i32 @bar(i8* %0) + ret void +} + +; SYM: SYMBOL TABLE: +; SYM-NEXT: 00000000 df *DEBUG* 00000000 .file +; SYM-NEXT: 00000000 *UND* 00000000 ei +; SYM-NEXT: 00000000 l .text 00000091 .text +; SYM-NEXT: 00000000 g F .text (csect: .text) 00000000 .bar +; SYM-NEXT: 00000050 g F .text (csect: .text) 00000000 .foo +; SYM-NEXT: 00000094 l .text 00000013 .rodata.str1.1L...str +; SYM-NEXT: 000000a8 g O .data 00000004 con +; SYM-NEXT: 000000ac w O .data 00000004 wi +; SYM-NEXT: 000000b0 g O .data 00000004 i +; SYM-NEXT: 000000b4 g O .data 00000001 c +; SYM-NEXT: 000000b8 g O .data 00000004 ap +; SYM-NEXT: 000000bc g O .data 00000004 f +; SYM-NEXT: 000000c0 g O .data 00000008 ll +; SYM-NEXT: 000000c8 g O .data 0000000c bar +; SYM-NEXT: 000000d4 g O .data 0000000c foo +; SYM-NEXT: 000000e0 l .data 00000000 TOC +; SYM-NEXT: 000000e0 l O .data 00000004 si +; SYM-NEXT: 000000e4 l O .data 00000004 ei +; SYM-NEXT: 000000e8 l O .data 00000004 con +; SYM-NEXT: 000000ec l O *COM* 00000004 si + +; SYM-DES: SYMBOL TABLE: +; SYM-DES-NEXT: 00000000 df *DEBUG* 00000000 (idx: 0) .file +; SYM-DES-NEXT: 00000000 *UND* 00000000 (idx: 1) ei[UA] +; SYM-DES-NEXT: 00000000 l .text 00000091 (idx: 3) .text[PR] +; SYM-DES-NEXT: 00000000 g F .text (csect: (idx: 3) .text[PR]) 00000000 (idx: 5) .bar +; SYM-DES-NEXT: 00000050 g F .text (csect: (idx: 3) .text[PR]) 00000000 (idx: 7) .foo +; SYM-DES-NEXT: 00000094 l .text 00000013 (idx: 9) .rodata.str1.1L...str[RO] +; SYM-DES-NEXT: 000000a8 g O .data 00000004 (idx: 11) con[RW] +; SYM-DES-NEXT: 000000ac w O .data 00000004 (idx: 13) wi[RW] +; SYM-DES-NEXT: 000000b0 g O .data 00000004 (idx: 15) i[RW] +; SYM-DES-NEXT: 000000b4 g O .data 00000001 (idx: 17) c[RW] +; SYM-DES-NEXT: 000000b8 g O .data 00000004 (idx: 19) ap[RW] +; SYM-DES-NEXT: 000000bc g O .data 00000004 (idx: 21) f[RW] +; SYM-DES-NEXT: 000000c0 g O .data 00000008 (idx: 23) ll[RW] +; SYM-DES-NEXT: 000000c8 g O .data 0000000c (idx: 25) bar[DS] +; SYM-DES-NEXT: 000000d4 g O .data 0000000c (idx: 27) foo[DS] +; SYM-DES-NEXT: 000000e0 l .data 00000000 (idx: 29) TOC[TC0] +; SYM-DES-NEXT: 000000e0 l O .data 00000004 (idx: 31) si[TC] +; SYM-DES-NEXT: 000000e4 l O .data 00000004 (idx: 33) ei[TC] +; SYM-DES-NEXT: 000000e8 l O .data 00000004 (idx: 35) con[TC] +; SYM-DES-NEXT: 000000ec l O *COM* 00000004 (idx: 37) si[BS] diff --git a/llvm/tools/llvm-objdump/XCOFFDump.h b/llvm/tools/llvm-objdump/XCOFFDump.h --- a/llvm/tools/llvm-objdump/XCOFFDump.h +++ b/llvm/tools/llvm-objdump/XCOFFDump.h @@ -20,6 +20,10 @@ getXCOFFSymbolCsectSMC(const object::XCOFFObjectFile *Obj, const object::SymbolRef &Sym); +Optional +getXCOFFSymbolContainingSymbolRef(const object::XCOFFObjectFile *Obj, + const object::SymbolRef &Sym); + bool isLabel(const object::XCOFFObjectFile *Obj, const object::SymbolRef &Sym); std::string getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo, diff --git a/llvm/tools/llvm-objdump/XCOFFDump.cpp b/llvm/tools/llvm-objdump/XCOFFDump.cpp --- a/llvm/tools/llvm-objdump/XCOFFDump.cpp +++ b/llvm/tools/llvm-objdump/XCOFFDump.cpp @@ -58,6 +58,24 @@ return CsectAuxEntOrErr.get().getStorageMappingClass(); } +Optional +objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile *Obj, + const SymbolRef &Sym) { + + const XCOFFSymbolRef SymRef = Obj->toSymbolRef(Sym.getRawDataRefImpl()); + if (!SymRef.isCsectSymbol()) + return None; + + Expected CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef(); + if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel()) + return None; + uint32_t Idx = + static_cast(CsectAuxEntOrErr.get().getSectionOrLength()); + DataRefImpl DRI; + DRI.p = Obj->getSymbolByIndex(Idx); + return SymbolRef(DRI, Obj); +} + bool objdump::isLabel(const XCOFFObjectFile *Obj, const SymbolRef &Sym) { const XCOFFSymbolRef SymRef = Obj->toSymbolRef(Sym.getRawDataRefImpl()); diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -2050,21 +2050,56 @@ } else if (Common) { outs() << "*COM*"; } else if (Section == O->section_end()) { - outs() << "*UND*"; + if (O->isXCOFF()) { + XCOFFSymbolRef XCOFFSym = dyn_cast(O)->toSymbolRef( + Symbol.getRawDataRefImpl()); + if (XCOFF::N_DEBUG == XCOFFSym.getSectionNumber()) + outs() << "*DEBUG*"; + else + outs() << "*UND*"; + } else + outs() << "*UND*"; } else { StringRef SegmentName = getSegmentName(MachO, *Section); if (!SegmentName.empty()) outs() << SegmentName << ","; StringRef SectionName = unwrapOrError(Section->getName(), FileName); outs() << SectionName; - } + if (O->isXCOFF()) { + Optional SymRef = getXCOFFSymbolContainingSymbolRef( + dyn_cast(O), Symbol); + if (SymRef) { + + Expected NameOrErr = SymRef.getValue().getName(); + + if (NameOrErr) { + outs() << " (csect:"; + std::string SymName(NameOrErr.get()); + + if (Demangle) + SymName = demangle(SymName); + + if (SymbolDescription) + SymName = getXCOFFSymbolDescription( + createSymbolInfo(O, SymRef.getValue()), SymName); - if (Common || O->isELF()) { - uint64_t Val = - Common ? Symbol.getAlignment() : ELFSymbolRef(Symbol).getSize(); - outs() << '\t' << format(Fmt, Val); + outs() << ' ' << SymName; + outs() << ") "; + } else + reportWarning(toString(NameOrErr.takeError()), FileName); + } + } } + if (Common) + outs() << '\t' << format(Fmt, Symbol.getAlignment()); + else if (O->isXCOFF()) + outs() << '\t' + << format(Fmt, dyn_cast(O)->getSymbolSize( + Symbol.getRawDataRefImpl())); + else if (O->isELF()) + outs() << '\t' << format(Fmt, ELFSymbolRef(Symbol).getSize()); + if (O->isELF()) { if (!SymbolVersions.empty()) { const VersionEntry &Ver = @@ -2096,10 +2131,14 @@ outs() << " .hidden"; } + std::string SymName(Name); if (Demangle) - outs() << ' ' << demangle(std::string(Name)) << '\n'; - else - outs() << ' ' << Name << '\n'; + SymName = demangle(SymName); + + if (O->isXCOFF() && SymbolDescription) + SymName = getXCOFFSymbolDescription(createSymbolInfo(O, Symbol), SymName); + + outs() << ' ' << SymName << '\n'; } static void printUnwindInfo(const ObjectFile *O) {