Line data Source code
1 : //===-- Decompressor.cpp --------------------------------------------------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 :
10 : #include "llvm/Object/Decompressor.h"
11 : #include "llvm/BinaryFormat/ELF.h"
12 : #include "llvm/Object/ELFObjectFile.h"
13 : #include "llvm/Support/Compression.h"
14 : #include "llvm/Support/DataExtractor.h"
15 : #include "llvm/Support/Endian.h"
16 :
17 : using namespace llvm;
18 : using namespace llvm::support::endian;
19 : using namespace object;
20 :
21 46 : Expected<Decompressor> Decompressor::create(StringRef Name, StringRef Data,
22 : bool IsLE, bool Is64Bit) {
23 46 : if (!zlib::isAvailable())
24 0 : return createError("zlib is not available");
25 :
26 46 : Decompressor D(Data);
27 46 : Error Err = isGnuStyle(Name) ? D.consumeCompressedGnuHeader()
28 46 : : D.consumeCompressedZLibHeader(Is64Bit, IsLE);
29 46 : if (Err)
30 : return std::move(Err);
31 : return D;
32 : }
33 :
34 46 : Decompressor::Decompressor(StringRef Data)
35 46 : : SectionData(Data), DecompressedSize(0) {}
36 :
37 27 : Error Decompressor::consumeCompressedGnuHeader() {
38 : if (!SectionData.startswith("ZLIB"))
39 5 : return createError("corrupted compressed section header");
40 :
41 22 : SectionData = SectionData.substr(4);
42 :
43 : // Consume uncompressed section size (big-endian 8 bytes).
44 22 : if (SectionData.size() < 8)
45 0 : return createError("corrupted uncompressed section size");
46 22 : DecompressedSize = read64be(SectionData.data());
47 22 : SectionData = SectionData.substr(8);
48 :
49 : return Error::success();
50 : }
51 :
52 19 : Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit,
53 : bool IsLittleEndian) {
54 : using namespace ELF;
55 19 : uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr);
56 19 : if (SectionData.size() < HdrSize)
57 1 : return createError("corrupted compressed section header");
58 :
59 : DataExtractor Extractor(SectionData, IsLittleEndian, 0);
60 18 : uint32_t Offset = 0;
61 18 : if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
62 : : sizeof(Elf32_Word)) !=
63 : ELFCOMPRESS_ZLIB)
64 0 : return createError("unsupported compression type");
65 :
66 : // Skip Elf64_Chdr::ch_reserved field.
67 18 : if (Is64Bit)
68 18 : Offset += sizeof(Elf64_Word);
69 :
70 18 : DecompressedSize = Extractor.getUnsigned(
71 : &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word));
72 18 : SectionData = SectionData.substr(HdrSize);
73 : return Error::success();
74 : }
75 :
76 22101 : bool Decompressor::isGnuStyle(StringRef Name) {
77 22101 : return Name.startswith(".zdebug");
78 : }
79 :
80 21688 : bool Decompressor::isCompressed(const object::SectionRef &Section) {
81 21688 : StringRef Name;
82 21688 : if (Section.getName(Name))
83 : return false;
84 21674 : return Section.isCompressed() || isGnuStyle(Name);
85 : }
86 :
87 0 : bool Decompressor::isCompressedELFSection(uint64_t Flags, StringRef Name) {
88 0 : return (Flags & ELF::SHF_COMPRESSED) || isGnuStyle(Name);
89 : }
90 :
91 40 : Error Decompressor::decompress(MutableArrayRef<char> Buffer) {
92 40 : size_t Size = Buffer.size();
93 40 : return zlib::uncompress(SectionData, Buffer.data(), Size);
94 : }
|