diff --git a/lld/test/ELF/got32-i386.s b/lld/test/ELF/got32-i386.s --- a/lld/test/ELF/got32-i386.s +++ b/lld/test/ELF/got32-i386.s @@ -15,7 +15,7 @@ ## 73728 == 0x12000 == ADDR(.got) # CHECK: Sections: # CHECK: Name Size VMA -# CHECK: .got 00000004 00000000004020fc +# CHECK: .got 00000004 004020fc # CHECK: _start: # CHECK-NEXT: 4010f5: 8b 1d {{.*}} movl 4202748, %ebx diff --git a/lld/test/ELF/got32x-i386.s b/lld/test/ELF/got32x-i386.s --- a/lld/test/ELF/got32x-i386.s +++ b/lld/test/ELF/got32x-i386.s @@ -33,8 +33,8 @@ ## 73728 == 0x12000 == ADDR(.got) # CHECK: Sections: -# CHECK: Name Size VMA -# CHECK: .got.plt 0000000c 0000000000403134 +# CHECK: Name Size VMA +# CHECK: .got.plt 0000000c 00403134 # CHECK: _start: # CHECK-NEXT: 401115: 8b 05 {{.*}} movl 4202800, %eax # CHECK-NEXT: 40111b: 8b 1d {{.*}} movl 4202800, %ebx diff --git a/llvm/test/tools/llvm-objdump/section-headers-address-width.test b/llvm/test/tools/llvm-objdump/section-headers-address-width.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/section-headers-address-width.test @@ -0,0 +1,49 @@ +## Check that objdump -h only prints the necessary amount of bytes for +## addresses. + +# RUN: yaml2obj %s --docnum=1 -o %t-32bit.o +# RUN: yaml2obj %s --docnum=2 -o %t-64bit.o + +# RUN: llvm-objdump -h --show-lma %t-32bit.o \ +# RUN: | FileCheck %s --check-prefix=32 --strict-whitespace +# 32: {{^}}Idx Name Size VMA LMA Type{{$}} +# 32: {{^}} 1 .foo 00000000 00000400 00000400 TEXT{{$}} + +# RUN: llvm-objdump -h %t-32bit.o \ +# RUN: | FileCheck %s --check-prefix=32-NO-LMA --strict-whitespace +# 32-NO-LMA: {{^}}Idx Name Size VMA Type{{$}} +# 32-NO-LMA: {{^}} 1 .foo 00000000 00000400 TEXT{{$}} + +# RUN: llvm-objdump -h --show-lma %t-64bit.o \ +# RUN: | FileCheck %s --check-prefix=64 --strict-whitespace +# 64: {{^}}Idx Name Size VMA LMA Type{{$}} +# 64: {{^}} 1 .foo 00000000 0000000000000400 0000000000000400 TEXT{{$}} + +# RUN: llvm-objdump -h %t-64bit.o \ +# RUN: | FileCheck %s --check-prefix=64-NO-LMA --strict-whitespace +# 64-NO-LMA: {{^}}Idx Name Size VMA Type{{$}} +# 64-NO-LMA: {{^}} 1 .foo 00000000 0000000000000400 TEXT{{$}} + +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +Sections: + - Name: .foo + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_EXECINSTR] + Address: 0x400 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .foo + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_EXECINSTR] + Address: 0x400 diff --git a/llvm/test/tools/llvm-objdump/section-headers-name-width.test b/llvm/test/tools/llvm-objdump/section-headers-name-width.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/section-headers-name-width.test @@ -0,0 +1,60 @@ +## The name field automatically expands past the default 13 columns when a +## section name is longer than that. +## Note: check with and without --show-lma to make sure resizing happens in +## both cases. + +# RUN: yaml2obj %s --docnum=1 -o %t-name13chars.o +# RUN: llvm-objdump -h --show-lma %t-name13chars.o \ +# RUN: | FileCheck %s --check-prefix=NAME-13 --strict-whitespace +# RUN: llvm-objdump -h %t-name13chars.o \ +# RUN: | FileCheck %s --check-prefix=NAME-13 --strict-whitespace + +# NAME-13: Sections: +# NAME-13-NEXT: {{^}}Idx Name Size +# NAME-13-NEXT: {{^}} 0 00000000 +# NAME-13-NEXT: {{^}} 1 .foo 00000000 +# NAME-13-NEXT: {{^}} 2 .thirteenchar 00000000 +# NAME-13-NEXT: {{^}} 3 .bar 00000000 + +## Including a section with a name of length 14 expands the width of the "Name" +## column. +# RUN: yaml2obj %s --docnum=2 -o %t-name14chars.o +# RUN: llvm-objdump -h --show-lma %t-name14chars.o \ +# RUN: | FileCheck %s --check-prefix=NAME-14 --strict-whitespace +# RUN: llvm-objdump -h %t-name14chars.o \ +# RUN: | FileCheck %s --check-prefix=NAME-14 --strict-whitespace + +# NAME-14: Sections: +# NAME-14-NEXT: {{^}}Idx Name Size +# NAME-14-NEXT: {{^}} 0 00000000 +# NAME-14-NEXT: {{^}} 1 .foo 00000000 +# NAME-14-NEXT: {{^}} 2 .fourteenchars 00000000 +# NAME-14-NEXT: {{^}} 3 .bar 00000000 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .thirteenchar + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .foo + Type: SHT_PROGBITS + - Name: .fourteenchars + Type: SHT_PROGBITS + - Name: .bar + Type: SHT_PROGBITS diff --git a/llvm/test/tools/llvm-objdump/section-headers-spacing.test b/llvm/test/tools/llvm-objdump/section-headers-spacing.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/section-headers-spacing.test @@ -0,0 +1,42 @@ +## Check leading and trailing whitespace for full lines. + +# RUN: yaml2obj %s -o %t-whitespace.o +# RUN: llvm-objdump -h --show-lma %t-whitespace.o \ +# RUN: | FileCheck %s --check-prefix=WHITESPACE --strict-whitespace +# RUN: llvm-objdump -h %t-whitespace.o \ +# RUN: | FileCheck %s --check-prefix=WHITESPACE-NO-LMA --strict-whitespace + +# WHITESPACE: {{^}}Sections:{{$}} +# WHITESPACE-NEXT: {{^}}Idx Name Size VMA LMA Type{{$}} +# WHITESPACE-NEXT: {{^}} 0 00000000 0000000000000000 0000000000000000 {{$}} +# WHITESPACE-NEXT: {{^}} 1 .text 00000000 0000000000000000 0000000000000000 TEXT{{$}} +# WHITESPACE-NEXT: {{^}} 2 .data 00000000 0000000000000000 0000000000000000 DATA{{$}} +# WHITESPACE-NEXT: {{^}} 3 .bss 00000000 0000000000000000 0000000000000000 BSS{{$}} +# WHITESPACE-NEXT: {{^}} 4 .other 00000000 0000000000000000 0000000000000000 {{$}} + +# WHITESPACE-NO-LMA: {{^}}Sections:{{$}} +# WHITESPACE-NO-LMA-NEXT: {{^}}Idx Name Size VMA Type{{$}} +# WHITESPACE-NO-LMA-NEXT: {{^}} 0 00000000 0000000000000000 {{$}} +# WHITESPACE-NO-LMA-NEXT: {{^}} 1 .text 00000000 0000000000000000 TEXT{{$}} +# WHITESPACE-NO-LMA-NEXT: {{^}} 2 .data 00000000 0000000000000000 DATA{{$}} +# WHITESPACE-NO-LMA-NEXT: {{^}} 3 .bss 00000000 0000000000000000 BSS{{$}} +# WHITESPACE-NO-LMA-NEXT: {{^}} 4 .other 00000000 0000000000000000 {{$}} + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_EXECINSTR] + - Name: .data + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_WRITE] + - Name: .bss + Type: SHT_NOBITS + Flags: [SHF_ALLOC, SHF_WRITE] + - Name: .other + Type: SHT_REL diff --git a/llvm/test/tools/llvm-objdump/wasm.txt b/llvm/test/tools/llvm-objdump/wasm.txt --- a/llvm/test/tools/llvm-objdump/wasm.txt +++ b/llvm/test/tools/llvm-objdump/wasm.txt @@ -1,14 +1,14 @@ # RUN: llvm-objdump -h %p/Inputs/trivial.obj.wasm | FileCheck %s # CHECK: Sections: -# CHECK-NEXT: Idx Name Size VMA Type -# CHECK-NEXT: 0 TYPE 00000011 0000000000000000 -# CHECK-NEXT: 1 IMPORT 0000005d 0000000000000000 -# CHECK-NEXT: 2 FUNCTION 00000003 0000000000000000 -# CHECK-NEXT: 3 CODE 00000024 0000000000000000 TEXT -# CHECK-NEXT: 4 DATA 0000001c 0000000000000000 DATA -# CHECK-NEXT: 5 linking 0000006d 0000000000000000 -# CHECK-NEXT: 6 reloc.CODE 0000000f 0000000000000000 +# CHECK-NEXT: Idx Name Size VMA Type +# CHECK-NEXT: 0 TYPE 00000011 00000000 +# CHECK-NEXT: 1 IMPORT 0000005d 00000000 +# CHECK-NEXT: 2 FUNCTION 00000003 00000000 +# CHECK-NEXT: 3 CODE 00000024 00000000 TEXT +# CHECK-NEXT: 4 DATA 0000001c 00000000 DATA +# CHECK-NEXT: 5 linking 0000006d 00000000 +# CHECK-NEXT: 6 reloc.CODE 0000000f 00000000 # RUN: llvm-objdump -p %p/Inputs/trivial.obj.wasm | FileCheck %s -check-prefix CHECK-HEADER diff --git a/llvm/test/tools/llvm-objdump/xcoff-section-headers.test b/llvm/test/tools/llvm-objdump/xcoff-section-headers.test --- a/llvm/test/tools/llvm-objdump/xcoff-section-headers.test +++ b/llvm/test/tools/llvm-objdump/xcoff-section-headers.test @@ -12,12 +12,12 @@ # CHECK: xcoff-section-headers.o: file format aixcoff-rs6000 # CHECK: Sections: -# CHECK: Idx Name Size VMA Type -# CHECK: 1 .text 00000080 0000000000000000 TEXT -# CHECK: 2 .data 00000024 0000000000000080 DATA -# CHECK: 3 .bss 00000004 00000000000000a4 BSS -# CHECK: 4 .tdata 00000008 0000000000000000 DATA -# CHECK: 5 .tbss 00000004 0000000000000008 BSS +# CHECK: Idx Name Size VMA Type +# CHECK: 0 .text 00000080 00000000 TEXT +# CHECK: 1 .data 00000024 00000080 DATA +# CHECK: 2 .bss 00000004 000000a4 BSS +# CHECK: 3 .tdata 00000008 00000000 DATA +# CHECK: 4 .tbss 00000004 00000008 BSS # xcoff-section-headers.o Compiled with IBM XL C/C++ for AIX, V16.1.0 # test.c: @@ -32,10 +32,10 @@ # LONG: xcoff-long-sec-names.o: file format aixcoff-rs6000 # LONG: Sections: -# LONG: Idx Name Size VMA Type -# LONG: 1 .dwarnge 00000004 0000000000000000 -# LONG: 2 .dwpbnms 00000004 0000000000000000 -# LONG: 3 .dwpbtyp 00000004 0000000000000000 +# LONG: Idx Name Size VMA Type +# LONG: 0 .dwarnge 00000004 00000000 +# LONG: 1 .dwpbnms 00000004 00000000 +# LONG: 2 .dwpbtyp 00000004 00000000 # xcoff-long-sec-names.o was generated by assembling the following .s file: # .dwsect 0x30000 # .dwpbnms section diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -79,7 +79,12 @@ }; // Various helper functions. -SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O); + +// The optional index parameter is to keep track of which section index this is. +// This may be different than the actual section number, as some sections may be +// filtered (e.g. symbol tables). +SectionFilter ToolSectionFilter(llvm::object::ObjectFile const &O, + uint64_t *Idx = nullptr); Error getELFRelocationValueString(const object::ELFObjectFileBase *Obj, const object::RelocationRef &Rel, 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 @@ -342,14 +342,19 @@ typedef std::vector> SectionSymbolsTy; -static bool shouldKeep(object::SectionRef S) { +struct FilterResult { + bool Keep; + bool IncrementIndex; +}; + +static FilterResult checkSectionFilter(object::SectionRef S) { if (FilterSections.empty()) - return true; + return {/*Keep=*/true, /*Increment=*/true}; Expected SecNameOrErr = S.getName(); if (!SecNameOrErr) { consumeError(SecNameOrErr.takeError()); - return false; + return {/*Keep=*/false, /*Increment=*/false}; } StringRef SecName = *SecNameOrErr; @@ -357,11 +362,25 @@ // no name (such as the section with index 0) here. if (!SecName.empty()) FoundSectionSet.insert(SecName); - return is_contained(FilterSections, SecName); + + // Only show the section if it's in the FilterSections list, but always + // increment so the indexing is stable. + return {/*Keep=*/is_contained(FilterSections, SecName), /*Increment=*/true}; } -SectionFilter ToolSectionFilter(object::ObjectFile const &O) { - return SectionFilter([](object::SectionRef S) { return shouldKeep(S); }, O); +SectionFilter ToolSectionFilter(object::ObjectFile const &O, uint64_t *Idx) { + // Start at UINT64_MAX so that the first index returned after an increment is + // zero (after the unsigned wrap). + if (Idx != nullptr) + *Idx = UINT64_MAX; + return SectionFilter( + [Idx](object::SectionRef S) { + auto Result = checkSectionFilter(S); + if (Idx != nullptr && Result.IncrementIndex) + *Idx += 1; + return Result.Keep; + }, + O); } std::string getFileNameForError(const object::Archive::Child &C, @@ -967,7 +986,7 @@ std::map> Ret; for (SectionRef Sec : Obj.sections()) { section_iterator Relocated = Sec.getRelocatedSection(); - if (Relocated == Obj.section_end() || !shouldKeep(*Relocated)) + if (Relocated == Obj.section_end() || !checkSectionFilter(*Relocated).Keep) continue; std::vector &V = Ret[*Relocated]; for (const RelocationRef &R : Sec.relocations()) @@ -1650,38 +1669,60 @@ return ShowLMA; } +static size_t getMaxSectionNameWidth(const ObjectFile *Obj) { + // Default column width for names is 13 even if no names are that long. + size_t MaxWidth = 13; + for (const SectionRef &Section : ToolSectionFilter(*Obj)) { + StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName()); + MaxWidth = std::max(MaxWidth, Name.size()); + } + return MaxWidth; +} + void printSectionHeaders(const ObjectFile *Obj) { + size_t NameWidth = getMaxSectionNameWidth(Obj); + size_t AddressWidth = 2 * Obj->getBytesInAddress(); bool HasLMAColumn = shouldDisplayLMA(Obj); if (HasLMAColumn) outs() << "Sections:\n" - "Idx Name Size VMA LMA " - "Type\n"; + "Idx " + << left_justify("Name", NameWidth) << " Size " + << left_justify("VMA", AddressWidth) << " " + << left_justify("LMA", AddressWidth) << " Type\n"; else outs() << "Sections:\n" - "Idx Name Size VMA Type\n"; + "Idx " + << left_justify("Name", NameWidth) << " Size " + << left_justify("VMA", AddressWidth) << " Type\n"; - for (const SectionRef &Section : ToolSectionFilter(*Obj)) { + uint64_t Idx; + for (const SectionRef &Section : ToolSectionFilter(*Obj, &Idx)) { StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName()); uint64_t VMA = Section.getAddress(); if (shouldAdjustVA(Section)) VMA += AdjustVMA; uint64_t Size = Section.getSize(); - bool Text = Section.isText(); - bool Data = Section.isData(); - bool BSS = Section.isBSS(); - std::string Type = (std::string(Text ? "TEXT " : "") + - (Data ? "DATA " : "") + (BSS ? "BSS" : "")); + + std::vector SectionTypes; + if (Section.isText()) + SectionTypes.push_back("TEXT"); + if (Section.isData()) + SectionTypes.push_back("DATA"); + if (Section.isBSS()) + SectionTypes.push_back("BSS"); + std::string Type = llvm::join(SectionTypes, " "); if (HasLMAColumn) - outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %016" PRIx64 - " %s\n", - (unsigned)Section.getIndex(), Name.str().c_str(), Size, - VMA, getELFSectionLMA(Section), Type.c_str()); + outs() << format("%3d %-*s %08" PRIx64 " ", Idx, NameWidth, + Name.str().c_str(), Size) + << format_hex_no_prefix(VMA, AddressWidth) << " " + << format_hex_no_prefix(getELFSectionLMA(Section), AddressWidth) + << " " << Type << "\n"; else - outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n", - (unsigned)Section.getIndex(), Name.str().c_str(), Size, - VMA, Type.c_str()); + outs() << format("%3d %-*s %08" PRIx64 " ", Idx, NameWidth, + Name.str().c_str(), Size) + << format_hex_no_prefix(VMA, AddressWidth) << " " << Type << "\n"; } outs() << "\n"; }