1 //===-- Decompressor.cpp --------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Object/Decompressor.h"
10 #include "llvm/BinaryFormat/ELF.h"
11 #include "llvm/Object/ELFObjectFile.h"
12 #include "llvm/Support/Compression.h"
13 #include "llvm/Support/DataExtractor.h"
14 #include "llvm/Support/Endian.h"
17 using namespace llvm::support::endian
;
18 using namespace object
;
20 Expected
<Decompressor
> Decompressor::create(StringRef Name
, StringRef Data
,
21 bool IsLE
, bool Is64Bit
) {
22 if (!zlib::isAvailable())
23 return createError("zlib is not available");
26 Error Err
= isGnuStyle(Name
) ? D
.consumeCompressedGnuHeader()
27 : D
.consumeCompressedZLibHeader(Is64Bit
, IsLE
);
29 return std::move(Err
);
33 Decompressor::Decompressor(StringRef Data
)
34 : SectionData(Data
), DecompressedSize(0) {}
36 Error
Decompressor::consumeCompressedGnuHeader() {
37 if (!SectionData
.startswith("ZLIB"))
38 return createError("corrupted compressed section header");
40 SectionData
= SectionData
.substr(4);
42 // Consume uncompressed section size (big-endian 8 bytes).
43 if (SectionData
.size() < 8)
44 return createError("corrupted uncompressed section size");
45 DecompressedSize
= read64be(SectionData
.data());
46 SectionData
= SectionData
.substr(8);
48 return Error::success();
51 Error
Decompressor::consumeCompressedZLibHeader(bool Is64Bit
,
52 bool IsLittleEndian
) {
54 uint64_t HdrSize
= Is64Bit
? sizeof(Elf64_Chdr
) : sizeof(Elf32_Chdr
);
55 if (SectionData
.size() < HdrSize
)
56 return createError("corrupted compressed section header");
58 DataExtractor
Extractor(SectionData
, IsLittleEndian
, 0);
60 if (Extractor
.getUnsigned(&Offset
, Is64Bit
? sizeof(Elf64_Word
)
61 : sizeof(Elf32_Word
)) !=
63 return createError("unsupported compression type");
65 // Skip Elf64_Chdr::ch_reserved field.
67 Offset
+= sizeof(Elf64_Word
);
69 DecompressedSize
= Extractor
.getUnsigned(
70 &Offset
, Is64Bit
? sizeof(Elf64_Xword
) : sizeof(Elf32_Word
));
71 SectionData
= SectionData
.substr(HdrSize
);
72 return Error::success();
75 bool Decompressor::isGnuStyle(StringRef Name
) {
76 return Name
.startswith(".zdebug");
79 bool Decompressor::isCompressed(const object::SectionRef
&Section
) {
80 if (Section
.isCompressed())
83 Expected
<StringRef
> SecNameOrErr
= Section
.getName();
85 return isGnuStyle(*SecNameOrErr
);
87 consumeError(SecNameOrErr
.takeError());
91 bool Decompressor::isCompressedELFSection(uint64_t Flags
, StringRef Name
) {
92 return (Flags
& ELF::SHF_COMPRESSED
) || isGnuStyle(Name
);
95 Error
Decompressor::decompress(MutableArrayRef
<char> Buffer
) {
96 size_t Size
= Buffer
.size();
97 return zlib::uncompress(SectionData
, Buffer
.data(), Size
);