Index: test/tools/llvm-objcopy/ELF/cross-arch-headers.test =================================================================== --- test/tools/llvm-objcopy/ELF/cross-arch-headers.test +++ test/tools/llvm-objcopy/ELF/cross-arch-headers.test @@ -1,33 +1,50 @@ +# Show that the --output-format correctly configures both the main output file +# and DWO output. +# Note that we don't actually need any DWARF to produce the DWO file. + # RUN: yaml2obj %s > %t.o -# RUN: llvm-objcopy %t.o -O elf32-i386 %t.elf32_i386.o +# Without --output-format, the format should match the input. +# RUN: llvm-objcopy %t.o %t.default.o --split-dwo=%t.default.dwo +# RUN: llvm-readobj --file-headers %t.default.o | FileCheck %s --check-prefixes=CHECK,DEFAULT,32 +# RUN: llvm-readobj --file-headers %t.default.dwo | FileCheck %s --check-prefixes=CHECK,DEFAULT,32 + +# RUN: llvm-objcopy %t.o -O elf32-i386 %t.elf32_i386.o --split-dwo=%t.elf32_i386.dwo # RUN: llvm-readobj --file-headers %t.elf32_i386.o | FileCheck %s --check-prefixes=CHECK,I386,32,SYSV +# RUN: llvm-readobj --file-headers %t.elf32_i386.dwo | FileCheck %s --check-prefixes=CHECK,I386,32,SYSV -# RUN: llvm-objcopy %t.o -O elf32-powerpcle %t.elf32_ppcle.o +# RUN: llvm-objcopy %t.o -O elf32-powerpcle %t.elf32_ppcle.o --split-dwo=%t.elf32_ppcle.dwo # RUN: llvm-readobj --file-headers %t.elf32_ppcle.o | FileCheck %s --check-prefixes=CHECK,PPC,32,SYSV +# RUN: llvm-readobj --file-headers %t.elf32_ppcle.dwo | FileCheck %s --check-prefixes=CHECK,PPC,32,SYSV -# RUN: llvm-objcopy %t.o -O elf32-x86-64 %t.elf32_x86_64.o +# RUN: llvm-objcopy %t.o -O elf32-x86-64 %t.elf32_x86_64.o --split-dwo=%t.elf32_x86_64.dwo # RUN: llvm-readobj --file-headers %t.elf32_x86_64.o | FileCheck %s --check-prefixes=CHECK,X86-64,32,SYSV +# RUN: llvm-readobj --file-headers %t.elf32_x86_64.dwo | FileCheck %s --check-prefixes=CHECK,X86-64,32,SYSV -# RUN: llvm-objcopy %t.o -O elf64-powerpcle %t.elf64_ppcle.o +# RUN: llvm-objcopy %t.o -O elf64-powerpcle %t.elf64_ppcle.o --split-dwo=%t.elf64_ppcle.dwo # RUN: llvm-readobj --file-headers %t.elf64_ppcle.o | FileCheck %s --check-prefixes=CHECK,PPC64,64,SYSV +# RUN: llvm-readobj --file-headers %t.elf64_ppcle.dwo | FileCheck %s --check-prefixes=CHECK,PPC64,64,SYSV -# RUN: llvm-objcopy %t.o -O elf64-x86-64 %t.elf64_x86_64.o +# RUN: llvm-objcopy %t.o -O elf64-x86-64 %t.elf64_x86_64.o --split-dwo=%t.elf64_x86_64.dwo # RUN: llvm-readobj --file-headers %t.elf64_x86_64.o | FileCheck %s --check-prefixes=CHECK,X86-64,64,SYSV +# RUN: llvm-readobj --file-headers %t.elf64_x86_64.dwo | FileCheck %s --check-prefixes=CHECK,X86-64,64,SYSV -# RUN: llvm-objcopy %t.o -O elf64-x86-64-freebsd %t.elf64_x86_64_freebsd.o +# RUN: llvm-objcopy %t.o -O elf64-x86-64-freebsd %t.elf64_x86_64_freebsd.o --split-dwo=%t.elf64_x86_64_freebsd.dwo # RUN: llvm-readobj --file-headers %t.elf64_x86_64_freebsd.o | FileCheck %s --check-prefixes=CHECK,X86-64,64,FREEBSD +# RUN: llvm-readobj --file-headers %t.elf64_x86_64_freebsd.dwo | FileCheck %s --check-prefixes=CHECK,X86-64,64,FREEBSD -# RUN: llvm-objcopy %t.o -O elf32-i386-freebsd %t.elf32_i386_freebsd.o +# RUN: llvm-objcopy %t.o -O elf32-i386-freebsd %t.elf32_i386_freebsd.o --split-dwo=%t.elf32_i386_freebsd.dwo # RUN: llvm-readobj --file-headers %t.elf32_i386_freebsd.o | FileCheck %s --check-prefixes=CHECK,I386,32,FREEBSD +# RUN: llvm-readobj --file-headers %t.elf32_i386_freebsd.dwo | FileCheck %s --check-prefixes=CHECK,I386,32,FREEBSD !ELF FileHeader: Class: ELFCLASS32 Data: ELFDATA2LSB Type: ET_EXEC - Machine: EM_386 - OSABI: ELFOSABI_STANDALONE # Arbitrary non-zero value. + # Arbitrary values that do not match any value we convert to via --output-format. + Machine: EM_NONE + OSABI: ELFOSABI_STANDALONE Sections: - Name: .text Type: SHT_PROGBITS @@ -50,14 +67,16 @@ # 32-SAME: ELF32- # 64-SAME: ELF64- # I386-SAME: i386 -# PPC-SAME: ppc +# PPC-SAME: ppc{{$}} # PPC64-SAME: ppc64 # X86-64-SAME: x86-64 +# DEFAULT-SAME: unknown # I386-NEXT: Arch: i386 -# PPC-NEXT: Arch: powerpc +# PPC-NEXT: Arch: powerpc{{$}} # PPC64-NEXT: Arch: powerpc64le # X86-64-NEXT: Arch: x86_64 +# DEFAULT-NEXT: Arch: unknown # 32-NEXT: AddressSize: 32bit # 64-NEXT: AddressSize: 64bit @@ -68,11 +87,12 @@ # SYSV: OS/ABI: SystemV (0x0) # FREEBSD: OS/ABI: FreeBSD (0x9) +# DEFAULT: OS/ABI: Standalone (0xFF) -# I386: Machine: EM_386 -# PPC: Machine: EM_PPC -# PPC64: Machine: EM_PPC64 -# X86-64: Machine: EM_X86_64 +# I386: Machine: EM_386 (0x3) +# PPC: Machine: EM_PPC (0x14) +# PPC64: Machine: EM_PPC64 (0x15) +# X86-64: Machine: EM_X86_64 (0x3E) # 32: HeaderSize: 52 # 64: HeaderSize: 64 Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -438,13 +438,19 @@ void printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, uint32_t Sym, StringRef StrTable, uint32_t Bucket); void printRelocHeader(unsigned SType); - void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, - const Elf_Rela &R, bool IsRela); + const typename ELFT::Sym *getRelocationSymbol(const ELFO *Obj, const Elf_Rela &R, const Elf_Shdr *Symtab); + void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, const Elf_Rela &R, + bool IsRela); + void printRelocation(const ELFO *Obj, const Elf_Sym *Sym, const Elf_Rela &R, + bool IsRela); void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, StringRef StrTable, bool IsDynamic) override; std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *FirstSym); - void printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela); + const typename ELFT::Sym *getDynamicRelocationSymbol(const Elf_Rela &R, + const Elf_Shdr *Symtab); + void printDynamicRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, Elf_Rela R, + bool IsRela); bool checkTLSSections(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); bool checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); bool checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); @@ -2692,38 +2698,55 @@ template void GNUStyle::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, const Elf_Rela &R, bool IsRela) { - // First two fields are bit width dependent. The rest of them are after are - // fixed width. - unsigned Bias = ELFT::Is64Bits ? 8 : 0; - Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias}; - SmallString<32> RelocName; - Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName); + const Elf_Sym *Sym = getRelocationSymbol(R, SymTab); + // TODO: Get Symbol name + printRelocation(Obj, Sym, R, IsRela); +} + +template +const typename ELFT::Sym * +GNUStyle::getRelocationSymbol(const ELFO *Obj, const Elf_Rela &R, + const Elf_Shdr *SymTab) { const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&R, SymTab)); - std::string TargetName; + std::string SymbolName; if (Sym && Sym->getType() == ELF::STT_SECTION) { const Elf_Shdr *Sec = unwrapOrError( Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable())); - TargetName = unwrapOrError(Obj->getSectionName(Sec)); + SymbolName = unwrapOrError(Obj->getSectionName(Sec)); } else if (Sym) { StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); - TargetName = this->dumper()->getFullSymbolName( + SymbolName = this->dumper()->getFullSymbolName( Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */); } + return Sym; +} +template +void GNUStyle::printRelocation(const ELFO *Obj, const Elf_Sym *Sym, + const Elf_Rela &R, bool IsRela) { + // First two fields are bit width dependent. The rest of them are after are + // fixed width. + unsigned Bias = ELFT::Is64Bits ? 8 : 0; + Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias}; unsigned Width = ELFT::Is64Bits ? 16 : 8; Fields[0].Str = to_string(format_hex_no_prefix(R.r_offset, Width)); Fields[1].Str = to_string(format_hex_no_prefix(R.r_info, Width)); - Fields[2].Str = RelocName.str(); - if (Sym) + + SmallString<32> RelocName; + Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName); + Fields[2].Str = RelocName.c_str(); + + if (!SymbolName.empty() || (Sym && Sym->getValue() != 0)) Fields[3].Str = to_string(format_hex_no_prefix(Sym->getValue(), Width)); - Fields[4].Str = TargetName; - for (auto &F : Fields) - printField(F); + + Fields[4].Str = SymbolName; + for (auto &Field : Fields) + printField(Field); std::string Addend; if (IsRela) { int64_t RelAddend = R.r_addend; - if (Sym) { + if (!SymbolName.empty()) { if (R.r_addend < 0) { Addend = " - "; RelAddend = std::abs(RelAddend); @@ -2800,12 +2823,15 @@ Rela.r_offset = R.r_offset; Rela.r_info = R.r_info; Rela.r_addend = 0; - printRelocation(Obj, SymTab, Rela, false); + const Elf_Sym *Sym = getRelocationSymbol(Rela, SymTab); + printRelocation(Obj, Sym, Rela, false); } break; case ELF::SHT_RELA: - for (const auto &R : unwrapOrError(Obj->relas(&Sec))) - printRelocation(Obj, SymTab, R, true); + for (const auto &R : unwrapOrError(Obj->relas(&Sec))) { + const Elf_Sym *Sym = getRelocationSymbol(R, SymTab); + printRelocation(Obj, Sym, R, true); + } break; case ELF::SHT_RELR: case ELF::SHT_ANDROID_RELR: @@ -2814,13 +2840,17 @@ OS << to_string(format_hex_no_prefix(R, ELFT::Is64Bits ? 16 : 8)) << "\n"; else - for (const auto &R : RelrRelas) - printRelocation(Obj, SymTab, R, false); + for (const auto &R : RelrRelas) { + const Elf_Sym *Sym = getRelocationSymbol(R, SymTab); + printRelocation(Obj, Sym, R, false); + } break; case ELF::SHT_ANDROID_REL: case ELF::SHT_ANDROID_RELA: - for (const auto &R : AndroidRelas) - printRelocation(Obj, SymTab, R, Sec.sh_type == ELF::SHT_ANDROID_RELA); + for (const auto &R : AndroidRelas) { + const Elf_Sym *Sym = getRelocationSymbol(R, SymTab); + printRelocation(Obj, Sym, R, Sec.sh_type == ELF::SHT_ANDROID_RELA); + } break; } } @@ -3355,27 +3385,38 @@ } template -void GNUStyle::printDynamicRelocation(const ELFO *Obj, Elf_Rela R, - bool IsRela) { - unsigned Bias = ELFT::Is64Bits ? 8 : 0; +void GNUStyle::printDynamicRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, Elf_Rela R, + bool IsRela) { + const Elf_Sym *Sym = getDynamicRelocationSymbol(Obj, R, SymTab); + // TODO: Get Symbol name + printRelocation(Obj, Sym, R, IsRela); +} + +template +const typename ELFT::Sym * +GNUStyle::getRelocationSymbol(const ELFO *Obj, const Elf_Rela &R, + const Elf_Shdr *SymTab) { + uint32_t SymIndex = R.getSymbol(Obj->isMips64EL()); + const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; + std::string SymbolName = maybeDemangle( + unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()))); + return Sym; +} + // First two fields are bit width dependent. The rest of them are after are // fixed width. + unsigned Bias = ELFT::Is64Bits ? 8 : 0; Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias}; - unsigned Width = ELFT::Is64Bits ? 16 : 8; Fields[0].Str = to_string(format_hex_no_prefix(R.r_offset, Width)); Fields[1].Str = to_string(format_hex_no_prefix(R.r_info, Width)); - uint32_t SymIndex = R.getSymbol(Obj->isMips64EL()); - const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; SmallString<32> RelocName; Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName); Fields[2].Str = RelocName.c_str(); - std::string SymbolName = maybeDemangle( - unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()))); - if (!SymbolName.empty() || Sym->getValue() != 0) + if (!SymbolName.empty() || (Sym && Sym->getValue() != 0)) Fields[3].Str = to_string(format_hex_no_prefix(Sym->getValue(), Width)); Fields[4].Str = SymbolName; @@ -3392,7 +3433,8 @@ } else Addend = " + "; } - Addend += to_string(format_hex_no_prefix(RelAddend, 1)); + + Addend += to_hexString(RelAddend, false); } OS << Addend << "\n"; } @@ -3409,8 +3451,10 @@ Obj->base(), 1) << " contains " << DynRelaRegion.Size << " bytes:\n"; printRelocHeader(ELF::SHT_RELA); - for (const Elf_Rela &Rela : this->dumper()->dyn_relas()) - printDynamicRelocation(Obj, Rela, true); + for (const Elf_Rela &Rela : this->dumper()->dyn_relas()) { + const Elf_Sym *Sym = getDynamicRelocationSymbol(Rela, SymTab); + printDynamicRelocation(Obj, Sym, Rela, true); + } } if (DynRelRegion.Size > 0) { OS << "\n'REL' relocation section at offset " @@ -3423,7 +3467,8 @@ Rela.r_offset = Rel.r_offset; Rela.r_info = Rel.r_info; Rela.r_addend = 0; - printDynamicRelocation(Obj, Rela, false); + const Elf_Sym *Sym = getDynamicRelocationSymbol(Rela, SymTab); + printDynamicRelocation(Obj, Sym, Rela, false); } } if (DynRelrRegion.Size > 0) { @@ -3435,6 +3480,7 @@ Elf_Relr_Range Relrs = this->dumper()->dyn_relrs(); std::vector RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); for (const Elf_Rela &Rela : RelrRelas) { + const Elf_Sym *Sym = getDynamicRelocationSymbol(Rela, SymTab); printDynamicRelocation(Obj, Rela, false); } } @@ -3446,8 +3492,9 @@ } if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) { printRelocHeader(ELF::SHT_RELA); - for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef()) + for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef()) { printDynamicRelocation(Obj, Rela, true); + } } else { printRelocHeader(ELF::SHT_REL); for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef()) {