Index: test/tools/llvm-objcopy/ELF/overlapping-sections-in-segments.test =================================================================== --- test/tools/llvm-objcopy/ELF/overlapping-sections-in-segments.test +++ test/tools/llvm-objcopy/ELF/overlapping-sections-in-segments.test @@ -32,6 +32,7 @@ # CONTENTS: Hex dump of section '.first': # CONTENTS-NEXT: 0x00000000 01234567 +# CONTENTS-EMPTY: # CONTENTS-NEXT: Hex dump of section '.second': # CONTENTS-NEXT: 0x00000000 23456789 Index: test/tools/llvm-objcopy/ELF/overlapping-sections.test =================================================================== --- test/tools/llvm-objcopy/ELF/overlapping-sections.test +++ test/tools/llvm-objcopy/ELF/overlapping-sections.test @@ -37,6 +37,7 @@ # CONTENTS: Hex dump of section '.first': # CONTENTS-NEXT: 0x00000000 01234567 +# CONTENTS-EMPTY: # CONTENTS-NEXT: Hex dump of section '.second': # CONTENTS-NEXT: 0x00000000 23456789 Index: test/tools/llvm-readobj/hex-dump-multi.s =================================================================== --- /dev/null +++ test/tools/llvm-readobj/hex-dump-multi.s @@ -0,0 +1,21 @@ +# REQUIRES: x86-registered-target + +# RUN: llvm-mc -filetype=obj -triple x86_64 %s -o %t.o +# RUN: llvm-readobj -x .a -x .b %t.o | FileCheck %s +# RUN: llvm-readelf -x .a -x .b %t.o | FileCheck %s + +# CHECK: Hex dump of section '.a': +# CHECK-NEXT: 0x00000000 00 +# CHECK-EMPTY: +# CHECK-NEXT: Hex dump of section '.b': +# CHECK-NEXT: 0x00000000 01 +# CHECK-EMPTY: +# CHECK-NEXT: Hex dump of section '.a': +# CHECK-NEXT: 0x00000000 02 + +.section .a,"a",@progbits,unique,0 +.byte 0 +.section .b,"a",@progbits +.byte 1 +.section .a,"a",@progbits,unique,1 +.byte 2 Index: test/tools/llvm-readobj/hex-dump.test =================================================================== --- /dev/null +++ test/tools/llvm-readobj/hex-dump.test @@ -0,0 +1,59 @@ +## Test that the -x alias can be used flexibly. Create a baseline and ensure +## all other combinations are identical. +# RUN: llvm-readelf --file-header --hex-dump=.text \ +# RUN: %p/Inputs/trivial.obj.elf-x86-64 > %t.hexdump.out +# RUN: llvm-readelf -h --hex-dump .text %p/Inputs/trivial.obj.elf-x86-64 > %t.hexdump.1 +# RUN: llvm-readelf -h -x .text %p/Inputs/trivial.obj.elf-x86-64 > %t.hexdump.2 +# RUN: llvm-readelf -h -x=.text %p/Inputs/trivial.obj.elf-x86-64 > %t.hexdump.3 +# RUN: llvm-readelf -h -x.text %p/Inputs/trivial.obj.elf-x86-64 > %t.hexdump.4 +# RUN: llvm-readelf -hx .text %p/Inputs/trivial.obj.elf-x86-64 > %t.hexdump.5 +# RUN: llvm-readelf -hx=.text %p/Inputs/trivial.obj.elf-x86-64 > %t.hexdump.6 +# RUN: llvm-readelf -hx.text %p/Inputs/trivial.obj.elf-x86-64 > %t.hexdump.7 + +# RUN: cmp %t.hexdump.out %t.hexdump.1 +# RUN: cmp %t.hexdump.out %t.hexdump.2 +# RUN: cmp %t.hexdump.out %t.hexdump.3 +# RUN: cmp %t.hexdump.out %t.hexdump.4 +# RUN: cmp %t.hexdump.out %t.hexdump.5 +# RUN: cmp %t.hexdump.out %t.hexdump.6 +# RUN: cmp %t.hexdump.out %t.hexdump.7 + +# RUN: llvm-readelf -S %p/Inputs/trivial.obj.elf-x86-64 | FileCheck %s --check-prefix=ELF-SEC + +## Both 9 and .strtab refer to .strtab. Test we dump the section only once. +# RUN: llvm-readobj -x 9 -x 9 -x .strtab -x .strtab %p/Inputs/trivial.obj.elf-x86-64 2>&1 | \ +# RUN: FileCheck %s --check-prefix=ELF +# RUN: llvm-readobj -x 9 -x .strtab -x 10 -x not_exist \ +# RUN: %p/Inputs/trivial.obj.elf-x86-64 2>&1 | FileCheck %s --check-prefixes=ELF-WARN,ELF + +# ELF-SEC: [ 9] .strtab + +# ELF-WARN: warning: could not find section 'not_exist' +# ELF-WARN: warning: could not find section 10 +# ELF: Hex dump of section '.strtab': +# ELF-NEXT: 0x00000000 00747269 7669616c 2e6c6c00 6d61696e .trivial.ll.main +# ELF-NEXT: 0x00000010 002e4c2e 73747200 70757473 00536f6d ..L.str.puts.Som +# ELF-NEXT: 0x00000020 654f7468 65724675 6e637469 6f6e005f eOtherFunction._ +# ELF-NEXT: 0x00000030 474c4f42 414c5f4f 46465345 545f5441 GLOBAL_OFFSET_TA +# ELF-NEXT: 0x00000040 424c455f 00 BLE_. +# ELF-NOT: {{.}} + +## Below we test -x can be used for other binary formats. + +# RUN: llvm-readobj -x 1 %p/Inputs/trivial.obj.coff-x86-64 \ +# RUN: | FileCheck %s --check-prefix COFF + +# COFF: 0x00000000 4883ec28 488d0d00 000000e8 00000000 H..(H........... +# COFF: 0x00000010 e8000000 0031c048 83c428c3 .....1.H..(. + +# RUN: llvm-readobj -x 1 %p/Inputs/trivial.obj.macho-x86-64 \ +# RUN: | FileCheck %s --check-prefix MACHO + +# MACHO: 0x00000000 50488d3d 00000000 e8000000 00e80000 PH.=............ +# MACHO: 0x00000010 000031c0 5ac3 ..1.Z. + +# RUN: llvm-readobj -x 1 %p/Inputs/trivial.obj.wasm \ +# RUN: | FileCheck %s --check-prefix WASM + +# WASM: 0x00000000 04600001 7f60017f 017f6000 0060017f .`...`....`..`.. +# WASM: 0x00000010 00 . Index: test/tools/llvm-readobj/hexdump.test =================================================================== --- test/tools/llvm-readobj/hexdump.test +++ /dev/null @@ -1,32 +0,0 @@ -// Check dumping of the hexadecimal bytes of a section. -RUN: llvm-readobj -x .text %p/../../Object/Inputs/hello-world.elf-x86-64 | FileCheck %s - -CHECK: Hex dump of section '.text': -CHECK-NEXT: {{^}}0x00400460 - -// Test that the -x alias can be used flexibly. Create a baseline and ensure -// all other combinations are identical. -RUN: llvm-readelf --file-header --hex-dump=.text \ -RUN: %p/../../Object/Inputs/hello-world.elf-x86-64 > %t.hexdump.out -RUN: llvm-readelf -h --hex-dump .text \ -RUN: %p/../../Object/Inputs/hello-world.elf-x86-64 > %t.hexdump.1 -RUN: llvm-readelf -h -x .text \ -RUN: %p/../../Object/Inputs/hello-world.elf-x86-64 > %t.hexdump.2 -RUN: llvm-readelf -h -x=.text \ -RUN: %p/../../Object/Inputs/hello-world.elf-x86-64 > %t.hexdump.3 -RUN: llvm-readelf -h -x.text \ -RUN: %p/../../Object/Inputs/hello-world.elf-x86-64 > %t.hexdump.4 -RUN: llvm-readelf -hx .text \ -RUN: %p/../../Object/Inputs/hello-world.elf-x86-64 > %t.hexdump.5 -RUN: llvm-readelf -hx=.text \ -RUN: %p/../../Object/Inputs/hello-world.elf-x86-64 > %t.hexdump.6 -RUN: llvm-readelf -hx.text \ -RUN: %p/../../Object/Inputs/hello-world.elf-x86-64 > %t.hexdump.7 - -RUN: cmp %t.hexdump.out %t.hexdump.1 -RUN: cmp %t.hexdump.out %t.hexdump.2 -RUN: cmp %t.hexdump.out %t.hexdump.3 -RUN: cmp %t.hexdump.out %t.hexdump.4 -RUN: cmp %t.hexdump.out %t.hexdump.5 -RUN: cmp %t.hexdump.out %t.hexdump.6 -RUN: cmp %t.hexdump.out %t.hexdump.7 Index: test/tools/llvm-readobj/print-hex.test =================================================================== --- test/tools/llvm-readobj/print-hex.test +++ /dev/null @@ -1,26 +0,0 @@ -RUN: llvm-readobj -x .strtab %p/Inputs/trivial.obj.elf-x86-64 \ -RUN: | FileCheck %s --check-prefix ELF - -ELF: 0x00000000 00747269 7669616c 2e6c6c00 6d61696e .trivial.ll.main -ELF: 0x00000010 002e4c2e 73747200 70757473 00536f6d ..L.str.puts.Som -ELF: 0x00000020 654f7468 65724675 6e637469 6f6e005f eOtherFunction._ -ELF: 0x00000030 474c4f42 414c5f4f 46465345 545f5441 GLOBAL_OFFSET_TA -ELF: 0x00000040 424c455f 00 BLE_. - -RUN: llvm-readobj -x 1 %p/Inputs/trivial.obj.coff-x86-64 \ -RUN: | FileCheck %s --check-prefix COFF - -COFF: 0x00000000 4883ec28 488d0d00 000000e8 00000000 H..(H........... -COFF: 0x00000010 e8000000 0031c048 83c428c3 .....1.H..(. - -RUN: llvm-readobj -x 1 %p/Inputs/trivial.obj.macho-x86-64 \ -RUN: | FileCheck %s --check-prefix MACHO - -MACHO: 0x00000000 50488d3d 00000000 e8000000 00e80000 PH.=............ -MACHO: 0x00000010 000031c0 5ac3 ..1.Z. - -RUN: llvm-readobj -x 1 %p/Inputs/trivial.obj.wasm \ -RUN: | FileCheck %s --check-prefix WASM - -WASM: 0x00000000 04600001 7f60017f 017f6000 0060017f .`...`....`..`.. -WASM: 0x00000010 00 . Index: test/tools/llvm-readobj/string-dump-multi.s =================================================================== --- /dev/null +++ test/tools/llvm-readobj/string-dump-multi.s @@ -0,0 +1,21 @@ +# REQUIRES: x86-registered-target + +# RUN: llvm-mc -filetype=obj -triple x86_64 %s -o %t.o +# RUN: llvm-readobj -p .a -p .b %t.o | FileCheck %s +# RUN: llvm-readelf -p .a -p .b %t.o | FileCheck %s + +# CHECK: String dump of section '.a': +# CHECK-NEXT: [ 0] 0 +# CHECK-EMPTY: +# CHECK-NEXT: String dump of section '.b': +# CHECK-NEXT: [ 0] 1 +# CHECK-EMPTY: +# CHECK-NEXT: String dump of section '.a': +# CHECK-NEXT: [ 0] 2 + +.section .a,"a",@progbits,unique,0 +.asciz "0" +.section .b,"a",@progbits +.asciz "1" +.section .a,"a",@progbits,unique,1 +.asciz "2" Index: test/tools/llvm-readobj/string-dump.test =================================================================== --- test/tools/llvm-readobj/string-dump.test +++ test/tools/llvm-readobj/string-dump.test @@ -9,9 +9,9 @@ # flag (-p), with different prefix modes (-p .foo, -p=.foo, -p.foo), and with # the value being a index section number instead of a section name. # RUN: llvm-readobj -p=.strings -p=.not_null_terminated %t > %t.readobj.1 -# RUN: llvm-readobj -p.strings -p.not_null_terminated %t > %t.readobj.2 +# RUN: llvm-readobj -p.strings -p.strings -p.not_null_terminated %t > %t.readobj.2 # RUN: llvm-readobj --string-dump=1 --string-dump=2 %t > %t.readobj.3 -# RUN: llvm-readobj -p1 -p2 %t > %t.readobj.4 +# RUN: llvm-readobj -p1 -p1 -p2 %t > %t.readobj.4 # RUN: llvm-readobj -p=1 -p=2 %t > %t.readobj.5 # RUN: cmp %t.readobj.out %t.readobj.1 @@ -45,19 +45,20 @@ # CHECK-NEXT: [ 5] are # CHECK-NEXT: [ 9] some # CHECK-NEXT: [ e] strings +# CHECK-EMPTY: # CHECK-NEXT: String dump of section '.not_null_terminated': # CHECK-NEXT: [ 0] no # CHECK-NEXT: [ 3] null{{$}} # CHECK-NOT: {{.}} -# RUN: not llvm-readobj --string-dump=does_not_exist %t 2>&1 | FileCheck %s --check-prefix=ERR1 -# RUN: not llvm-readobj --string-dump=42 %t 2>&1 | FileCheck %s --check-prefix=ERR2 +# RUN: llvm-readobj --string-dump=does_not_exist %t 2>&1 | FileCheck %s --check-prefix=WARN1 +# RUN: llvm-readobj --string-dump=42 %t 2>&1 | FileCheck %s --check-prefix=WARN2 -# RUN: not llvm-readelf --string-dump=does_not_exist %t 2>&1 | FileCheck %s --check-prefix=ERR1 -# RUN: not llvm-readelf --string-dump=42 %t 2>&1 | FileCheck %s --check-prefix=ERR2 +# RUN: llvm-readelf --string-dump=does_not_exist %t 2>&1 | FileCheck %s --check-prefix=WARN1 +# RUN: llvm-readelf --string-dump=42 %t 2>&1 | FileCheck %s --check-prefix=WARN2 -# ERR1: error: could not find section 'does_not_exist' -# ERR2: error: could not find section '42' +# WARN1: warning: could not find section 'does_not_exist' +# WARN2: warning: could not find section 42 --- !ELF FileHeader: Index: tools/llvm-readobj/ObjDumper.h =================================================================== --- tools/llvm-readobj/ObjDumper.h +++ tools/llvm-readobj/ObjDumper.h @@ -104,8 +104,10 @@ virtual void printStackMap() const = 0; - void printSectionAsString(const object::ObjectFile *Obj, StringRef SecName); - void printSectionAsHex(const object::ObjectFile *Obj, StringRef SecName); + void printSectionsAsString(const object::ObjectFile *Obj, + ArrayRef Sections); + void printSectionsAsHex(const object::ObjectFile *Obj, + ArrayRef Sections); protected: ScopedPrinter &W; Index: tools/llvm-readobj/ObjDumper.cpp =================================================================== --- tools/llvm-readobj/ObjDumper.cpp +++ tools/llvm-readobj/ObjDumper.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" +#include namespace llvm { @@ -32,115 +33,129 @@ W << (isPrint(Start[i]) ? static_cast(Start[i]) : '.'); } -static Expected -getSecNameOrIndexAsSecRef(const object::ObjectFile *Obj, StringRef SecName) { - char *StrPtr; - long SectionIndex = strtol(SecName.data(), &StrPtr, 10); - long SecIndex; - if (Obj->isELF()) - SecIndex = 0; - else - SecIndex = 1; +static std::vector +getSectionRefsByNameOrIndex(const object::ObjectFile *Obj, + ArrayRef Sections) { + std::vector Ret; + std::map SecNames; + std::map SecIndices; + unsigned SecIndex; + for (StringRef Section : Sections) { + if (!Section.getAsInteger(0, SecIndex)) + SecIndices.emplace(SecIndex, false); + else + SecNames.emplace(Section, false); + } + + SecIndex = Obj->isELF() ? 0 : 1; for (object::SectionRef SecRef : Obj->sections()) { - if (*StrPtr) { - StringRef SectionName; - - if (std::error_code E = SecRef.getName(SectionName)) - return errorCodeToError(E); - - if (SectionName == SecName) - return SecRef; - } else if (SecIndex == SectionIndex) - return SecRef; - + StringRef SecName; + error(SecRef.getName(SecName)); + auto NameIt = SecNames.find(SecName); + if (NameIt != SecNames.end()) + NameIt->second = true; + auto IndexIt = SecIndices.find(SecIndex); + if (IndexIt != SecIndices.end()) + IndexIt->second = true; + if (NameIt != SecNames.end() || IndexIt != SecIndices.end()) + Ret.push_back(SecRef); SecIndex++; } - return make_error( - formatv("could not find section '{0}'", SecName), - object::object_error::parse_failed); + + for (const std::pair &S : SecNames) + if (!S.second) + reportWarning(formatv("could not find section '{0}'", S.first).str()); + for (std::pair S : SecIndices) + if (!S.second) + reportWarning(formatv("could not find section {0}", S.first).str()); + + return Ret; } -void ObjDumper::printSectionAsString(const object::ObjectFile *Obj, - StringRef SecName) { - Expected SectionRefOrError = - getSecNameOrIndexAsSecRef(Obj, SecName); - if (!SectionRefOrError) - error(std::move(SectionRefOrError)); - object::SectionRef Section = *SectionRefOrError; - StringRef SectionName; +void ObjDumper::printSectionsAsString(const object::ObjectFile *Obj, + ArrayRef Sections) { + bool First = true; + for (object::SectionRef Section : + getSectionRefsByNameOrIndex(Obj, Sections)) { + StringRef SectionName; + if (std::error_code E = Section.getName(SectionName)) + error(E); + if (!First) + W.startLine() << '\n'; + First = false; + W.startLine() << "String dump of section '" << SectionName << "':\n"; - if (std::error_code E = Section.getName(SectionName)) - error(E); - W.startLine() << "String dump of section '" << SectionName << "':\n"; + StringRef SectionContent = unwrapOrError(Section.getContents()); - StringRef SectionContent = unwrapOrError(Section.getContents()); + const uint8_t *SecContent = SectionContent.bytes_begin(); + const uint8_t *CurrentWord = SecContent; + const uint8_t *SecEnd = SectionContent.bytes_end(); - const uint8_t *SecContent = SectionContent.bytes_begin(); - const uint8_t *CurrentWord = SecContent; - const uint8_t *SecEnd = SectionContent.bytes_end(); - - while (CurrentWord <= SecEnd) { - size_t WordSize = strnlen(reinterpret_cast(CurrentWord), - SecEnd - CurrentWord); - if (!WordSize) { - CurrentWord++; - continue; + while (CurrentWord <= SecEnd) { + size_t WordSize = strnlen(reinterpret_cast(CurrentWord), + SecEnd - CurrentWord); + if (!WordSize) { + CurrentWord++; + continue; + } + W.startLine() << format("[%6tx] ", CurrentWord - SecContent); + printAsPrintable(W.startLine(), CurrentWord, WordSize); + W.startLine() << '\n'; + CurrentWord += WordSize + 1; } - W.startLine() << format("[%6tx] ", CurrentWord - SecContent); - printAsPrintable(W.startLine(), CurrentWord, WordSize); - W.startLine() << '\n'; - CurrentWord += WordSize + 1; } } -void ObjDumper::printSectionAsHex(const object::ObjectFile *Obj, - StringRef SecName) { - Expected SectionRefOrError = - getSecNameOrIndexAsSecRef(Obj, SecName); - if (!SectionRefOrError) - error(std::move(SectionRefOrError)); - object::SectionRef Section = *SectionRefOrError; - StringRef SectionName; +void ObjDumper::printSectionsAsHex(const object::ObjectFile *Obj, + ArrayRef Sections) { + bool First = true; + for (object::SectionRef Section : + getSectionRefsByNameOrIndex(Obj, Sections)) { + StringRef SectionName; + if (std::error_code E = Section.getName(SectionName)) + error(E); + if (!First) + W.startLine() << '\n'; + First = false; + W.startLine() << "Hex dump of section '" << SectionName << "':\n"; - if (std::error_code E = Section.getName(SectionName)) - error(E); - W.startLine() << "Hex dump of section '" << SectionName << "':\n"; + StringRef SectionContent = unwrapOrError(Section.getContents()); + const uint8_t *SecContent = SectionContent.bytes_begin(); + const uint8_t *SecEnd = SecContent + SectionContent.size(); - StringRef SectionContent = unwrapOrError(Section.getContents()); - const uint8_t *SecContent = SectionContent.bytes_begin(); - const uint8_t *SecEnd = SecContent + SectionContent.size(); + for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) { + const uint8_t *TmpSecPtr = SecPtr; + uint8_t i; + uint8_t k; - for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) { - const uint8_t *TmpSecPtr = SecPtr; - uint8_t i; - uint8_t k; - - W.startLine() << format_hex(Section.getAddress() + (SecPtr - SecContent), - 10); - W.startLine() << ' '; - for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) { - for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) { - uint8_t Val = *(reinterpret_cast(TmpSecPtr)); - W.startLine() << format_hex_no_prefix(Val, 2); - } + W.startLine() << format_hex(Section.getAddress() + (SecPtr - SecContent), + 10); W.startLine() << ' '; + for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) { + for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) { + uint8_t Val = *(reinterpret_cast(TmpSecPtr)); + W.startLine() << format_hex_no_prefix(Val, 2); + } + W.startLine() << ' '; + } + + // We need to print the correct amount of spaces to match the format. + // We are adding the (4 - i) last rows that are 8 characters each. + // Then, the (4 - i) spaces that are in between the rows. + // Least, if we cut in a middle of a row, we add the remaining characters, + // which is (8 - (k * 2)). + if (i < 4) + W.startLine() << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)), + ' '); + + TmpSecPtr = SecPtr; + for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i) + W.startLine() << (isPrint(TmpSecPtr[i]) + ? static_cast(TmpSecPtr[i]) + : '.'); + + W.startLine() << '\n'; } - - // We need to print the correct amount of spaces to match the format. - // We are adding the (4 - i) last rows that are 8 characters each. - // Then, the (4 - i) spaces that are in between the rows. - // Least, if we cut in a middle of a row, we add the remaining characters, - // which is (8 - (k * 2)). - if (i < 4) - W.startLine() << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)), - ' '); - - TmpSecPtr = SecPtr; - for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i) - W.startLine() << (isPrint(TmpSecPtr[i]) ? static_cast(TmpSecPtr[i]) - : '.'); - - W.startLine() << '\n'; } } Index: tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- tools/llvm-readobj/llvm-readobj.cpp +++ tools/llvm-readobj/llvm-readobj.cpp @@ -495,13 +495,9 @@ if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE) Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping); if (!opts::StringDump.empty()) - llvm::for_each(opts::StringDump, [&Dumper, Obj](StringRef SectionName) { - Dumper->printSectionAsString(Obj, SectionName); - }); + Dumper->printSectionsAsString(Obj, opts::StringDump); if (!opts::HexDump.empty()) - llvm::for_each(opts::HexDump, [&Dumper, Obj](StringRef SectionName) { - Dumper->printSectionAsHex(Obj, SectionName); - }); + Dumper->printSectionsAsHex(Obj, opts::HexDump); if (opts::HashTable) Dumper->printHashTable(); if (opts::GnuHashTable)