Skip to content

Commit 26d71d9

Browse files
authored
[llvm-readobj,ELF] Support --decompress/-z (#82594)
When a section has the SHF_COMPRESSED flag, -p/-x dump the compressed content by default. In GNU readelf, if --decompress/-z is specified, -p/-x will dump the decompressed content. This patch implements the option. Close #82507
1 parent 87b1e73 commit 26d71d9

File tree

10 files changed

+209
-6
lines changed

10 files changed

+209
-6
lines changed

llvm/docs/CommandGuide/llvm-readelf.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ OPTIONS
3838
Display the contents of the basic block address map section(s), which contain the
3939
address of each function, along with the relative offset of each basic block.
4040

41+
.. option:: --decompress, -z
42+
43+
Dump decompressed section content when used with ``-x`` or ``-p``.
44+
If the section(s) are not compressed, they are displayed as is.
45+
4146
.. option:: --demangle, -C
4247

4348
Display demangled symbol names in the output.

llvm/docs/CommandGuide/llvm-readobj.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ file formats.
5656

5757
Display the address-significance table.
5858

59+
.. option:: --decompress, -z
60+
61+
Dump decompressed section content when used with ``-x`` or ``-p``.
62+
If the section(s) are not compressed, they are displayed as is.
63+
5964
.. option:: --expand-relocs
6065

6166
When used with :option:`--relocs`, display each relocation in an expanded
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# UNSUPPORTED: zlib
2+
# RUN: yaml2obj %s -o %t
3+
# RUN: llvm-readobj -z -p .a -x .b %t 2>&1 | FileCheck %s -DFILE=%t
4+
5+
# CHECK: String dump of section '.a':
6+
# CHECK-NEXT: warning: '[[FILE]]': LLVM was not built with LLVM_ENABLE_ZLIB or did not find zlib at build time
7+
# CHECK-NEXT: [ 0] .
8+
# CHECK-NEXT: [ 8] .
9+
# CHECK-NEXT: [ 10] .
10+
# CHECK-NEXT: [ 18] x.c.
11+
# CHECK-NEXT: [ 1e] .
12+
# CHECK-NEXT: [ 20] .
13+
# CHECK-NEXT: Hex dump of section '.b':
14+
# CHECK-NEXT: warning: '[[FILE]]': LLVM was not built with LLVM_ENABLE_ZLIB or did not find zlib at build time
15+
# CHECK-NEXT: 0x00000000 01000000 00000000 01000000 00000000 ................
16+
# CHECK-NEXT: 0x00000010 01000000 00000000 789c6304 00000200 ........x.c.....
17+
# CHECK-NEXT: 0x00000020 02 .
18+
19+
--- !ELF
20+
FileHeader:
21+
Class: ELFCLASS64
22+
Data: ELFDATA2LSB
23+
Type: ET_REL
24+
Sections:
25+
- Name: .a
26+
Type: SHT_PROGBITS
27+
Flags: [SHF_COMPRESSED]
28+
Content: 010000000000000001000000000000000100000000000000789c63040000020002
29+
- Name: .b
30+
Type: SHT_PROGBITS
31+
Flags: [SHF_COMPRESSED]
32+
Content: 010000000000000001000000000000000100000000000000789c63040000020002
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# REQUIRES: zlib
2+
## Test --decompress/-z.
3+
4+
# RUN: yaml2obj %s -o %t
5+
6+
# RUN: llvm-readelf -z -x .strings -x .not_null_terminated %t | FileCheck %s --check-prefix=HEX
7+
# RUN: llvm-readobj --decompress -p .strings -p .not_null_terminated %t | FileCheck %s --check-prefix=STR
8+
9+
# HEX: Hex dump of section '.strings':
10+
# HEX-NEXT: 0x00000000 68657265 00617265 00736f6d 65007374 here.are.some.st
11+
# HEX-NEXT: 0x00000010 72696e67 7300 rings.
12+
# HEX: Hex dump of section '.not_null_terminated':
13+
# HEX-NEXT: 0x00000000 6e6f006e 756c6c no.null
14+
15+
# STR: String dump of section '.strings':
16+
# STR-NEXT: [ 0] here
17+
# STR-NEXT: [ 5] are
18+
# STR-NEXT: [ 9] some
19+
# STR-NEXT: [ e] strings
20+
# STR-EMPTY:
21+
# STR-NEXT: String dump of section '.not_null_terminated':
22+
# STR-NEXT: [ 0] no
23+
# STR-NEXT: [ 3] null{{$}}
24+
# STR-NOT: {{.}}
25+
26+
# RUN: llvm-readobj -x .strings -p .not_null_terminated %t | FileCheck %s --check-prefix=COMPRESSED
27+
28+
# COMPRESSED: String dump of section '.not_null_terminated':
29+
# COMPRESSED-NEXT: [ 0] no
30+
# COMPRESSED-NEXT: [ 3] null
31+
# COMPRESSED-NEXT: Hex dump of section '.strings':
32+
# COMPRESSED-NEXT: 0x00000000 01000000 00000000 16000000 00000000 ................
33+
# COMPRESSED-NEXT: 0x00000010 00000000 00000000 789ccb48 2d4a6548 ........x..H-JeH
34+
# COMPRESSED-NEXT: 0x00000020 04e2e2fc 5c205152 9499975e cc000058 ....\ QR...^...X
35+
# COMPRESSED-NEXT: 0x00000030 2e079b ...
36+
37+
# RUN: llvm-readelf -z -p .invalid1 -x .invalid2 -x .invalid3 %t 2>&1 | FileCheck %s -DFILE=%t --check-prefix=INVALID
38+
39+
# INVALID: String dump of section '.invalid1':
40+
# INVALID-NEXT: warning: '[[FILE]]': corrupted compressed section header
41+
# INVALID-NEXT: [ 0] .
42+
# INVALID-NEXT: Hex dump of section '.invalid2':
43+
# INVALID-NEXT: warning: '[[FILE]]': zlib error: Z_DATA_ERROR
44+
# INVALID-NEXT: 0x00000000 01000000 00000000 16000000 00000000 ................
45+
# INVALID-NEXT: 0x00000010 00000000 00000000 78 ........x
46+
# INVALID-EMPTY:
47+
# INVALID-NEXT: Hex dump of section '.invalid3':
48+
# INVALID-NEXT: warning: '[[FILE]]': unsupported compression type (3)
49+
# INVALID-NEXT: 0x00000000 03000000 00000000 04000000 00000000 ................
50+
# INVALID-NEXT: 0x00000010 00000000 00000000 789c6360 ........x.c`
51+
52+
--- !ELF
53+
FileHeader:
54+
Class: ELFCLASS64
55+
Data: ELFDATA2LSB
56+
Type: ET_REL
57+
Sections:
58+
- Name: .strings
59+
Type: SHT_PROGBITS
60+
Flags: [SHF_COMPRESSED]
61+
Content: 010000000000000016000000000000000000000000000000789ccb482d4a654804e2e2fc5c2051529499975ecc0000582e079b
62+
- Name: .not_null_terminated
63+
Type: SHT_PROGBITS
64+
Content: 6e6f006e756c6c
65+
- Name: .invalid1
66+
Type: SHT_PROGBITS
67+
Flags: [SHF_COMPRESSED]
68+
Content: 01
69+
- Name: .invalid2
70+
Type: SHT_PROGBITS
71+
Flags: [SHF_COMPRESSED]
72+
Content: 01000000000000001600000000000000000000000000000078
73+
- Name: .invalid3
74+
Type: SHT_PROGBITS
75+
Flags: [SHF_COMPRESSED]
76+
Content: 030000000000000004000000000000000000000000000000789c6360
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# UNSUPPORTED: zstd
2+
# RUN: yaml2obj %s -o %t
3+
# RUN: llvm-readobj -z -p .a -x .b %t 2>&1 | FileCheck %s -DFILE=%t
4+
5+
# CHECK: String dump of section '.a':
6+
# CHECK-NEXT: warning: '[[FILE]]': LLVM was not built with LLVM_ENABLE_ZSTD or did not find zstd at build time
7+
# CHECK-NEXT: [ 0] .
8+
# CHECK-NEXT: [ 8] .
9+
# CHECK-NEXT: [ 10] .
10+
# CHECK-NEXT: [ 18] (./. ..
11+
# CHECK-NEXT: [ 21] .
12+
# CHECK-NEXT: Hex dump of section '.b':
13+
# CHECK-NEXT: warning: '[[FILE]]': LLVM was not built with LLVM_ENABLE_ZSTD or did not find zstd at build time
14+
# CHECK-NEXT: 0x00000000 02000000 00000000 01000000 00000000 ................
15+
# CHECK-NEXT: 0x00000010 01000000 00000000 28b52ffd 20010900 ........(./. ...
16+
# CHECK-NEXT: 0x00000020 0001 ..
17+
18+
--- !ELF
19+
FileHeader:
20+
Class: ELFCLASS64
21+
Data: ELFDATA2LSB
22+
Type: ET_REL
23+
Sections:
24+
- Name: .a
25+
Type: SHT_PROGBITS
26+
Flags: [SHF_COMPRESSED]
27+
Content: 02000000000000000100000000000000010000000000000028b52ffd200109000001
28+
- Name: .b
29+
Type: SHT_PROGBITS
30+
Flags: [SHF_COMPRESSED]
31+
Content: 02000000000000000100000000000000010000000000000028b52ffd200109000001
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# REQUIRES: zstd
2+
## Test --decompress/-z for zstd.
3+
4+
# RUN: yaml2obj %s -o %t
5+
6+
# RUN: llvm-readelf -z -x .strings %t | FileCheck %s --check-prefix=HEX
7+
# RUN: llvm-readobj --decompress -p .strings %t | FileCheck %s --check-prefix=STR
8+
9+
# HEX: Hex dump of section '.strings':
10+
# HEX-NEXT: 0x00000000 68657265 00617265 00736f6d 65007374 here.are.some.st
11+
# HEX-NEXT: 0x00000010 72696e67 7300 rings.
12+
13+
# STR: String dump of section '.strings':
14+
# STR-NEXT: [ 0] here
15+
# STR-NEXT: [ 5] are
16+
# STR-NEXT: [ 9] some
17+
# STR-NEXT: [ e] strings
18+
19+
--- !ELF
20+
FileHeader:
21+
Class: ELFCLASS64
22+
Data: ELFDATA2LSB
23+
Type: ET_REL
24+
Sections:
25+
- Name: .strings
26+
Type: SHT_PROGBITS
27+
Flags: [SHF_COMPRESSED]
28+
Content: 02000000000000001600000000000000000000000000000028b52ffd2016b10000686572650061726500736f6d6500737472696e677300

llvm/tools/llvm-readobj/ObjDumper.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "ObjDumper.h"
1515
#include "llvm-readobj.h"
1616
#include "llvm/Object/Archive.h"
17+
#include "llvm/Object/Decompressor.h"
1718
#include "llvm/Object/ObjectFile.h"
1819
#include "llvm/Support/Error.h"
1920
#include "llvm/Support/FormatVariadic.h"
@@ -142,8 +143,23 @@ getSectionRefsByNameOrIndex(const object::ObjectFile &Obj,
142143
return Ret;
143144
}
144145

146+
static void maybeDecompress(const object::ObjectFile &Obj,
147+
StringRef SectionName, StringRef &SectionContent,
148+
SmallString<0> &Out) {
149+
Expected<object::Decompressor> Decompressor = object::Decompressor::create(
150+
SectionName, SectionContent, Obj.isLittleEndian(), Obj.is64Bit());
151+
if (!Decompressor)
152+
reportWarning(Decompressor.takeError(), Obj.getFileName());
153+
else if (auto Err = Decompressor->resizeAndDecompress(Out))
154+
reportWarning(std::move(Err), Obj.getFileName());
155+
else
156+
SectionContent = Out;
157+
}
158+
145159
void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj,
146-
ArrayRef<std::string> Sections) {
160+
ArrayRef<std::string> Sections,
161+
bool Decompress) {
162+
SmallString<0> Out;
147163
bool First = true;
148164
for (object::SectionRef Section :
149165
getSectionRefsByNameOrIndex(Obj, Sections)) {
@@ -156,12 +172,16 @@ void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj,
156172

157173
StringRef SectionContent =
158174
unwrapOrError(Obj.getFileName(), Section.getContents());
175+
if (Decompress && Section.isCompressed())
176+
maybeDecompress(Obj, SectionName, SectionContent, Out);
159177
printAsStringList(SectionContent);
160178
}
161179
}
162180

163181
void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj,
164-
ArrayRef<std::string> Sections) {
182+
ArrayRef<std::string> Sections,
183+
bool Decompress) {
184+
SmallString<0> Out;
165185
bool First = true;
166186
for (object::SectionRef Section :
167187
getSectionRefsByNameOrIndex(Obj, Sections)) {
@@ -174,6 +194,8 @@ void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj,
174194

175195
StringRef SectionContent =
176196
unwrapOrError(Obj.getFileName(), Section.getContents());
197+
if (Decompress && Section.isCompressed())
198+
maybeDecompress(Obj, SectionName, SectionContent, Out);
177199
const uint8_t *SecContent = SectionContent.bytes_begin();
178200
const uint8_t *SecEnd = SecContent + SectionContent.size();
179201

llvm/tools/llvm-readobj/ObjDumper.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,9 @@ class ObjDumper {
175175
void printAsStringList(StringRef StringContent, size_t StringDataOffset = 0);
176176

177177
void printSectionsAsString(const object::ObjectFile &Obj,
178-
ArrayRef<std::string> Sections);
178+
ArrayRef<std::string> Sections, bool Decompress);
179179
void printSectionsAsHex(const object::ObjectFile &Obj,
180-
ArrayRef<std::string> Sections);
180+
ArrayRef<std::string> Sections, bool Decompress);
181181

182182
std::function<Error(const Twine &Msg)> WarningHandler;
183183
void reportUniqueWarning(Error Err) const;

llvm/tools/llvm-readobj/Opts.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def all : FF<"all", "Equivalent to setting: --file-header, --program-headers, --
2020
def arch_specific : FF<"arch-specific", "Display architecture-specific information">;
2121
def bb_addr_map : FF<"bb-addr-map", "Display the BB address map section">;
2222
def cg_profile : FF<"cg-profile", "Display call graph profile section">;
23+
def decompress : FF<"decompress", "Dump decompressed section content when used with -x or -p">;
2324
defm demangle : BB<"demangle", "Demangle symbol names", "Do not demangle symbol names (default)">;
2425
def dependent_libraries : FF<"dependent-libraries", "Display the dependent libraries section">;
2526
def dyn_relocations : FF<"dyn-relocations", "Display the dynamic relocation entries in the file">;
@@ -139,3 +140,4 @@ def : F<"u", "Alias for --unwind">, Alias<unwind>;
139140
def : F<"X", "Alias for --extra-sym-info">, Alias<extra_sym_info>, Group<grp_elf>;
140141
def : F<"V", "Alias for --version-info">, Alias<version_info>, Group<grp_elf>;
141142
def : JoinedOrSeparate<["-"], "x">, Alias<hex_dump_EQ>, HelpText<"Alias for --hex-dump">, MetaVarName<"<name or index>">;
143+
def : F<"z", "Alias for --decompress">, Alias<decompress>;

llvm/tools/llvm-readobj/llvm-readobj.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ static bool ArchSpecificInfo;
9797
static bool BBAddrMap;
9898
bool ExpandRelocs;
9999
static bool CGProfile;
100+
static bool Decompress;
100101
bool Demangle;
101102
static bool DependentLibraries;
102103
static bool DynRelocs;
@@ -212,6 +213,7 @@ static void parseOptions(const opt::InputArgList &Args) {
212213
opts::ArchSpecificInfo = Args.hasArg(OPT_arch_specific);
213214
opts::BBAddrMap = Args.hasArg(OPT_bb_addr_map);
214215
opts::CGProfile = Args.hasArg(OPT_cg_profile);
216+
opts::Decompress = Args.hasArg(OPT_decompress);
215217
opts::Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, false);
216218
opts::DependentLibraries = Args.hasArg(OPT_dependent_libraries);
217219
opts::DynRelocs = Args.hasArg(OPT_dyn_relocations);
@@ -439,9 +441,9 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
439441
Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols,
440442
opts::ExtraSymInfo, SymComp);
441443
if (!opts::StringDump.empty())
442-
Dumper->printSectionsAsString(Obj, opts::StringDump);
444+
Dumper->printSectionsAsString(Obj, opts::StringDump, opts::Decompress);
443445
if (!opts::HexDump.empty())
444-
Dumper->printSectionsAsHex(Obj, opts::HexDump);
446+
Dumper->printSectionsAsHex(Obj, opts::HexDump, opts::Decompress);
445447
if (opts::HashTable)
446448
Dumper->printHashTable();
447449
if (opts::GnuHashTable)

0 commit comments

Comments
 (0)