14bf30831SGeorge Rimar //===-- Decompressor.cpp --------------------------------------------------===//
24bf30831SGeorge Rimar //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64bf30831SGeorge Rimar //
74bf30831SGeorge Rimar //===----------------------------------------------------------------------===//
84bf30831SGeorge Rimar 
94bf30831SGeorge Rimar #include "llvm/Object/Decompressor.h"
10264b5d9eSZachary Turner #include "llvm/BinaryFormat/ELF.h"
11e72c195fSserge-sans-paille #include "llvm/Object/ObjectFile.h"
124bf30831SGeorge Rimar #include "llvm/Support/Compression.h"
134bf30831SGeorge Rimar #include "llvm/Support/DataExtractor.h"
146bda14b3SChandler Carruth #include "llvm/Support/Endian.h"
154bf30831SGeorge Rimar 
164bf30831SGeorge Rimar using namespace llvm;
174bf30831SGeorge Rimar using namespace llvm::support::endian;
184bf30831SGeorge Rimar using namespace object;
194bf30831SGeorge Rimar 
create(StringRef Name,StringRef Data,bool IsLE,bool Is64Bit)204bf30831SGeorge Rimar Expected<Decompressor> Decompressor::create(StringRef Name, StringRef Data,
214bf30831SGeorge Rimar                                             bool IsLE, bool Is64Bit) {
22ea61750cSCole Kissane   if (!compression::zlib::isAvailable())
234bf30831SGeorge Rimar     return createError("zlib is not available");
244bf30831SGeorge Rimar 
253ae41704SVedant Kumar   Decompressor D(Data);
26*141c9d77SFangrui Song   if (Error Err = D.consumeCompressedZLibHeader(Is64Bit, IsLE))
27c55cf4afSBill Wendling     return std::move(Err);
284bf30831SGeorge Rimar   return D;
294bf30831SGeorge Rimar }
304bf30831SGeorge Rimar 
Decompressor(StringRef Data)313ae41704SVedant Kumar Decompressor::Decompressor(StringRef Data)
323ae41704SVedant Kumar     : SectionData(Data), DecompressedSize(0) {}
334bf30831SGeorge Rimar 
consumeCompressedZLibHeader(bool Is64Bit,bool IsLittleEndian)344bf30831SGeorge Rimar Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit,
354bf30831SGeorge Rimar                                                 bool IsLittleEndian) {
364bf30831SGeorge Rimar   using namespace ELF;
374bf30831SGeorge Rimar   uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr);
384bf30831SGeorge Rimar   if (SectionData.size() < HdrSize)
394bf30831SGeorge Rimar     return createError("corrupted compressed section header");
404bf30831SGeorge Rimar 
414bf30831SGeorge Rimar   DataExtractor Extractor(SectionData, IsLittleEndian, 0);
42f26a70a5SIgor Kudrin   uint64_t Offset = 0;
434bf30831SGeorge Rimar   if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
444bf30831SGeorge Rimar                                              : sizeof(Elf32_Word)) !=
454bf30831SGeorge Rimar       ELFCOMPRESS_ZLIB)
464bf30831SGeorge Rimar     return createError("unsupported compression type");
474bf30831SGeorge Rimar 
484bf30831SGeorge Rimar   // Skip Elf64_Chdr::ch_reserved field.
494bf30831SGeorge Rimar   if (Is64Bit)
504bf30831SGeorge Rimar     Offset += sizeof(Elf64_Word);
514bf30831SGeorge Rimar 
524bf30831SGeorge Rimar   DecompressedSize = Extractor.getUnsigned(
534bf30831SGeorge Rimar       &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word));
544bf30831SGeorge Rimar   SectionData = SectionData.substr(HdrSize);
554bf30831SGeorge Rimar   return Error::success();
564bf30831SGeorge Rimar }
574bf30831SGeorge Rimar 
decompress(MutableArrayRef<uint8_t> Buffer)58e690137dSFangrui Song Error Decompressor::decompress(MutableArrayRef<uint8_t> Buffer) {
594bf30831SGeorge Rimar   size_t Size = Buffer.size();
60e690137dSFangrui Song   return compression::zlib::uncompress(arrayRefFromStringRef(SectionData),
61e690137dSFangrui Song                                        Buffer.data(), Size);
624bf30831SGeorge Rimar }
63