mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-07 18:21:58 +00:00

Decompressor intention is to reduce duplication of code. Currently LLD has own implementation of decompressor for compressed debug sections. This class helps to avoid it and share the code. LLD patch for reusing it is D28106 Differential revision: https://reviews.llvm.org/D28105 llvm-svn: 291675
103 lines
3.3 KiB
C++
103 lines
3.3 KiB
C++
//===-- Decompressor.cpp --------------------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Object/Decompressor.h"
|
|
#include "llvm/Object/ELFObjectFile.h"
|
|
#include "llvm/Support/Compression.h"
|
|
#include "llvm/Support/DataExtractor.h"
|
|
#include "llvm/Support/Endian.h"
|
|
#include "llvm/Support/ELF.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::support::endian;
|
|
using namespace object;
|
|
|
|
Expected<Decompressor> Decompressor::create(StringRef Name, StringRef Data,
|
|
bool IsLE, bool Is64Bit) {
|
|
if (!zlib::isAvailable())
|
|
return createError("zlib is not available");
|
|
|
|
Decompressor D(Data);
|
|
Error Err = isGnuStyle(Name) ? D.consumeCompressedGnuHeader()
|
|
: D.consumeCompressedZLibHeader(Is64Bit, IsLE);
|
|
if (Err)
|
|
return std::move(Err);
|
|
return D;
|
|
}
|
|
|
|
Decompressor::Decompressor(StringRef Data)
|
|
: SectionData(Data), DecompressedSize(0) {}
|
|
|
|
Error Decompressor::consumeCompressedGnuHeader() {
|
|
if (!SectionData.startswith("ZLIB"))
|
|
return createError("corrupted compressed section header");
|
|
|
|
SectionData = SectionData.substr(4);
|
|
|
|
// Consume uncompressed section size (big-endian 8 bytes).
|
|
if (SectionData.size() < 8)
|
|
return createError("corrupted uncompressed section size");
|
|
DecompressedSize = read64be(SectionData.data());
|
|
SectionData = SectionData.substr(8);
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit,
|
|
bool IsLittleEndian) {
|
|
using namespace ELF;
|
|
uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr);
|
|
if (SectionData.size() < HdrSize)
|
|
return createError("corrupted compressed section header");
|
|
|
|
DataExtractor Extractor(SectionData, IsLittleEndian, 0);
|
|
uint32_t Offset = 0;
|
|
if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
|
|
: sizeof(Elf32_Word)) !=
|
|
ELFCOMPRESS_ZLIB)
|
|
return createError("unsupported compression type");
|
|
|
|
// Skip Elf64_Chdr::ch_reserved field.
|
|
if (Is64Bit)
|
|
Offset += sizeof(Elf64_Word);
|
|
|
|
DecompressedSize = Extractor.getUnsigned(
|
|
&Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word));
|
|
SectionData = SectionData.substr(HdrSize);
|
|
return Error::success();
|
|
}
|
|
|
|
bool Decompressor::isGnuStyle(StringRef Name) {
|
|
return Name.startswith(".zdebug");
|
|
}
|
|
|
|
bool Decompressor::isCompressed(const object::SectionRef &Section) {
|
|
StringRef Name;
|
|
if (std::error_code E = Section.getName(Name))
|
|
return false;
|
|
return Section.isCompressed() || isGnuStyle(Name);
|
|
}
|
|
|
|
bool Decompressor::isCompressedELFSection(uint64_t Flags, StringRef Name) {
|
|
return (Flags & ELF::SHF_COMPRESSED) || isGnuStyle(Name);
|
|
}
|
|
|
|
Error Decompressor::decompress(SmallString<32> &Out) {
|
|
Out.resize(DecompressedSize);
|
|
return decompress({Out.data(), (size_t)DecompressedSize});
|
|
}
|
|
|
|
Error Decompressor::decompress(MutableArrayRef<char> Buffer) {
|
|
size_t Size = Buffer.size();
|
|
zlib::Status Status = zlib::uncompress(SectionData, Buffer.data(), Size);
|
|
if (Status != zlib::StatusOK)
|
|
return createError("decompression failed");
|
|
return Error::success();
|
|
}
|