Decompressor.cpp 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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. #include "llvm/Object/Decompressor.h"
  9. #include "llvm/BinaryFormat/ELF.h"
  10. #include "llvm/Object/ELFObjectFile.h"
  11. #include "llvm/Support/Compression.h"
  12. #include "llvm/Support/DataExtractor.h"
  13. #include "llvm/Support/Endian.h"
  14. using namespace llvm;
  15. using namespace llvm::support::endian;
  16. using namespace object;
  17. Expected<Decompressor> Decompressor::create(StringRef Name, StringRef Data,
  18. bool IsLE, bool Is64Bit) {
  19. if (!zlib::isAvailable())
  20. return createError("zlib is not available");
  21. Decompressor D(Data);
  22. Error Err = isGnuStyle(Name) ? D.consumeCompressedGnuHeader()
  23. : D.consumeCompressedZLibHeader(Is64Bit, IsLE);
  24. if (Err)
  25. return std::move(Err);
  26. return D;
  27. }
  28. Decompressor::Decompressor(StringRef Data)
  29. : SectionData(Data), DecompressedSize(0) {}
  30. Error Decompressor::consumeCompressedGnuHeader() {
  31. if (!SectionData.startswith("ZLIB"))
  32. return createError("corrupted compressed section header");
  33. SectionData = SectionData.substr(4);
  34. // Consume uncompressed section size (big-endian 8 bytes).
  35. if (SectionData.size() < 8)
  36. return createError("corrupted uncompressed section size");
  37. DecompressedSize = read64be(SectionData.data());
  38. SectionData = SectionData.substr(8);
  39. return Error::success();
  40. }
  41. Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit,
  42. bool IsLittleEndian) {
  43. using namespace ELF;
  44. uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr);
  45. if (SectionData.size() < HdrSize)
  46. return createError("corrupted compressed section header");
  47. DataExtractor Extractor(SectionData, IsLittleEndian, 0);
  48. uint64_t Offset = 0;
  49. if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
  50. : sizeof(Elf32_Word)) !=
  51. ELFCOMPRESS_ZLIB)
  52. return createError("unsupported compression type");
  53. // Skip Elf64_Chdr::ch_reserved field.
  54. if (Is64Bit)
  55. Offset += sizeof(Elf64_Word);
  56. DecompressedSize = Extractor.getUnsigned(
  57. &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word));
  58. SectionData = SectionData.substr(HdrSize);
  59. return Error::success();
  60. }
  61. bool Decompressor::isGnuStyle(StringRef Name) {
  62. return Name.startswith(".zdebug");
  63. }
  64. bool Decompressor::isCompressed(const object::SectionRef &Section) {
  65. if (Section.isCompressed())
  66. return true;
  67. Expected<StringRef> SecNameOrErr = Section.getName();
  68. if (SecNameOrErr)
  69. return isGnuStyle(*SecNameOrErr);
  70. consumeError(SecNameOrErr.takeError());
  71. return false;
  72. }
  73. bool Decompressor::isCompressedELFSection(uint64_t Flags, StringRef Name) {
  74. return (Flags & ELF::SHF_COMPRESSED) || isGnuStyle(Name);
  75. }
  76. Error Decompressor::decompress(MutableArrayRef<char> Buffer) {
  77. size_t Size = Buffer.size();
  78. return zlib::uncompress(SectionData, Buffer.data(), Size);
  79. }