1 //===-- Decompressor.cpp --------------------------------------------------===// 2 // 3 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/Object/Decompressor.h" 10 #include "llvm/ADT/StringExtras.h" 11 #include "llvm/BinaryFormat/ELF.h" 12 #include "llvm/Object/ObjectFile.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 Expected<Decompressor> Decompressor::create(StringRef Name, StringRef Data, 22 bool IsLE, bool Is64Bit) { 23 Decompressor D(Data); 24 if (Error Err = D.consumeCompressedHeader(Is64Bit, IsLE)) 25 return std::move(Err); 26 return D; 27 } 28 29 Decompressor::Decompressor(StringRef Data) 30 : SectionData(Data), DecompressedSize(0) {} 31 32 Error Decompressor::consumeCompressedHeader(bool Is64Bit, bool IsLittleEndian) { 33 using namespace ELF; 34 uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr); 35 if (SectionData.size() < HdrSize) 36 return createError("corrupted compressed section header"); 37 38 DataExtractor Extractor(SectionData, IsLittleEndian, 0); 39 uint64_t Offset = 0; 40 auto ChType = Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word) 41 : sizeof(Elf32_Word)); 42 switch (ChType) { 43 case ELFCOMPRESS_ZLIB: 44 CompressionType = DebugCompressionType::Zlib; 45 break; 46 case ELFCOMPRESS_ZSTD: 47 CompressionType = DebugCompressionType::Zstd; 48 break; 49 default: 50 return createError("unsupported compression type (" + Twine(ChType) + ")"); 51 } 52 if (const char *Reason = llvm::compression::getReasonIfUnsupported( 53 compression::formatFor(CompressionType))) 54 return createError(Reason); 55 56 // Skip Elf64_Chdr::ch_reserved field. 57 if (Is64Bit) 58 Offset += sizeof(Elf64_Word); 59 60 DecompressedSize = Extractor.getUnsigned( 61 &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word)); 62 SectionData = SectionData.substr(HdrSize); 63 return Error::success(); 64 } 65 66 Error Decompressor::decompress(MutableArrayRef<uint8_t> Output) { 67 return compression::decompress(CompressionType, 68 arrayRefFromStringRef(SectionData), 69 Output.data(), Output.size()); 70 } 71