blob: ec15e6f69ada77442f17654ff73d79098bbe479d [file] [log] [blame]
George Rimar4bf30832017-01-11 15:26:41 +00001//===-- Decompressor.cpp --------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
George Rimar4bf30832017-01-11 15:26:41 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/Object/Decompressor.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000010#include "llvm/BinaryFormat/ELF.h"
George Rimar4bf30832017-01-11 15:26:41 +000011#include "llvm/Object/ELFObjectFile.h"
12#include "llvm/Support/Compression.h"
13#include "llvm/Support/DataExtractor.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000014#include "llvm/Support/Endian.h"
George Rimar4bf30832017-01-11 15:26:41 +000015
16using namespace llvm;
17using namespace llvm::support::endian;
18using namespace object;
19
20Expected<Decompressor> Decompressor::create(StringRef Name, StringRef Data,
21 bool IsLE, bool Is64Bit) {
22 if (!zlib::isAvailable())
23 return createError("zlib is not available");
24
Vedant Kumar3ae41702017-09-05 22:04:00 +000025 Decompressor D(Data);
George Rimar4bf30832017-01-11 15:26:41 +000026 Error Err = isGnuStyle(Name) ? D.consumeCompressedGnuHeader()
27 : D.consumeCompressedZLibHeader(Is64Bit, IsLE);
28 if (Err)
29 return std::move(Err);
30 return D;
31}
32
Vedant Kumar3ae41702017-09-05 22:04:00 +000033Decompressor::Decompressor(StringRef Data)
34 : SectionData(Data), DecompressedSize(0) {}
George Rimar4bf30832017-01-11 15:26:41 +000035
36Error Decompressor::consumeCompressedGnuHeader() {
37 if (!SectionData.startswith("ZLIB"))
38 return createError("corrupted compressed section header");
39
40 SectionData = SectionData.substr(4);
41
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);
47
48 return Error::success();
49}
50
51Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit,
52 bool IsLittleEndian) {
53 using namespace ELF;
54 uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr);
55 if (SectionData.size() < HdrSize)
56 return createError("corrupted compressed section header");
57
58 DataExtractor Extractor(SectionData, IsLittleEndian, 0);
59 uint32_t Offset = 0;
60 if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
61 : sizeof(Elf32_Word)) !=
62 ELFCOMPRESS_ZLIB)
63 return createError("unsupported compression type");
64
65 // Skip Elf64_Chdr::ch_reserved field.
66 if (Is64Bit)
67 Offset += sizeof(Elf64_Word);
68
69 DecompressedSize = Extractor.getUnsigned(
70 &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word));
71 SectionData = SectionData.substr(HdrSize);
72 return Error::success();
73}
74
75bool Decompressor::isGnuStyle(StringRef Name) {
76 return Name.startswith(".zdebug");
77}
78
79bool Decompressor::isCompressed(const object::SectionRef &Section) {
80 StringRef Name;
Davide Italiano3b5edf42017-01-11 19:05:27 +000081 if (Section.getName(Name))
George Rimar4bf30832017-01-11 15:26:41 +000082 return false;
83 return Section.isCompressed() || isGnuStyle(Name);
84}
85
86bool Decompressor::isCompressedELFSection(uint64_t Flags, StringRef Name) {
87 return (Flags & ELF::SHF_COMPRESSED) || isGnuStyle(Name);
88}
89
George Rimar4bf30832017-01-11 15:26:41 +000090Error Decompressor::decompress(MutableArrayRef<char> Buffer) {
91 size_t Size = Buffer.size();
George Rimar167ca4a2017-01-17 15:45:07 +000092 return zlib::uncompress(SectionData, Buffer.data(), Size);
George Rimar4bf30832017-01-11 15:26:41 +000093}