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