LLDB  mainline
LZMA.cpp
Go to the documentation of this file.
1 //===-- LZMA.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 "lldb/Host/Config.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/Support/Error.h"
12 
13 #if LLDB_ENABLE_LZMA
14 #include <lzma.h>
15 #endif // LLDB_ENABLE_LZMA
16 
17 namespace lldb_private {
18 
19 namespace lzma {
20 
21 #if !LLDB_ENABLE_LZMA
22 bool isAvailable() { return false; }
23 llvm::Expected<uint64_t>
24 getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) {
25  llvm_unreachable("lzma::getUncompressedSize is unavailable");
26 }
27 
28 llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer,
29  llvm::SmallVectorImpl<uint8_t> &Uncompressed) {
30  llvm_unreachable("lzma::uncompress is unavailable");
31 }
32 
33 #else // LLDB_ENABLE_LZMA
34 
35 bool isAvailable() { return true; }
36 
37 static const char *convertLZMACodeToString(lzma_ret Code) {
38  switch (Code) {
39  case LZMA_STREAM_END:
40  return "lzma error: LZMA_STREAM_END";
41  case LZMA_NO_CHECK:
42  return "lzma error: LZMA_NO_CHECK";
43  case LZMA_UNSUPPORTED_CHECK:
44  return "lzma error: LZMA_UNSUPPORTED_CHECK";
45  case LZMA_GET_CHECK:
46  return "lzma error: LZMA_GET_CHECK";
47  case LZMA_MEM_ERROR:
48  return "lzma error: LZMA_MEM_ERROR";
49  case LZMA_MEMLIMIT_ERROR:
50  return "lzma error: LZMA_MEMLIMIT_ERROR";
51  case LZMA_FORMAT_ERROR:
52  return "lzma error: LZMA_FORMAT_ERROR";
53  case LZMA_OPTIONS_ERROR:
54  return "lzma error: LZMA_OPTIONS_ERROR";
55  case LZMA_DATA_ERROR:
56  return "lzma error: LZMA_DATA_ERROR";
57  case LZMA_BUF_ERROR:
58  return "lzma error: LZMA_BUF_ERROR";
59  case LZMA_PROG_ERROR:
60  return "lzma error: LZMA_PROG_ERROR";
61  default:
62  llvm_unreachable("unknown or unexpected lzma status code");
63  }
64 }
65 
66 llvm::Expected<uint64_t>
67 getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) {
68  lzma_stream_flags opts{};
69  if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) {
70  return llvm::createStringError(
71  llvm::inconvertibleErrorCode(),
72  "size of xz-compressed blob (%lu bytes) is smaller than the "
73  "LZMA_STREAM_HEADER_SIZE (%lu bytes)",
74  InputBuffer.size(), LZMA_STREAM_HEADER_SIZE);
75  }
76 
77  // Decode xz footer.
78  lzma_ret xzerr = lzma_stream_footer_decode(
79  &opts, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE).data());
80  if (xzerr != LZMA_OK) {
81  return llvm::createStringError(llvm::inconvertibleErrorCode(),
82  "lzma_stream_footer_decode()=%s",
83  convertLZMACodeToString(xzerr));
84  }
85  if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) {
86  return llvm::createStringError(
87  llvm::inconvertibleErrorCode(),
88  "xz-compressed buffer size (%lu bytes) too small (required at "
89  "least %lu bytes) ",
90  InputBuffer.size(), (opts.backward_size + LZMA_STREAM_HEADER_SIZE));
91  }
92 
93  // Decode xz index.
94  lzma_index *xzindex;
95  uint64_t memlimit(UINT64_MAX);
96  size_t inpos = 0;
97  xzerr = lzma_index_buffer_decode(
98  &xzindex, &memlimit, nullptr,
99  InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE + opts.backward_size)
100  .data(),
101  &inpos, InputBuffer.size());
102  if (xzerr != LZMA_OK) {
103  return llvm::createStringError(llvm::inconvertibleErrorCode(),
104  "lzma_index_buffer_decode()=%s",
105  convertLZMACodeToString(xzerr));
106  }
107 
108  // Get size of uncompressed file to construct an in-memory buffer of the
109  // same size on the calling end (if needed).
110  uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex);
111 
112  // Deallocate xz index as it is no longer needed.
113  lzma_index_end(xzindex, nullptr);
114 
115  return uncompressedSize;
116 }
117 
118 llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer,
119  llvm::SmallVectorImpl<uint8_t> &Uncompressed) {
120  llvm::Expected<uint64_t> uncompressedSize = getUncompressedSize(InputBuffer);
121 
122  if (auto err = uncompressedSize.takeError())
123  return err;
124 
125  Uncompressed.resize(*uncompressedSize);
126 
127  // Decompress xz buffer to buffer.
128  uint64_t memlimit = UINT64_MAX;
129  size_t inpos = 0;
130  size_t outpos = 0;
131  lzma_ret ret = lzma_stream_buffer_decode(
132  &memlimit, 0, nullptr, InputBuffer.data(), &inpos, InputBuffer.size(),
133  Uncompressed.data(), &outpos, Uncompressed.size());
134  if (ret != LZMA_OK) {
135  return llvm::createStringError(llvm::inconvertibleErrorCode(),
136  "lzma_stream_buffer_decode()=%s",
137  convertLZMACodeToString(ret));
138  }
139 
140  return llvm::Error::success();
141 }
142 
143 #endif // LLDB_ENABLE_LZMA
144 
145 } // end of namespace lzma
146 } // namespace lldb_private
lldb_private::lzma::uncompress
llvm::Error uncompress(llvm::ArrayRef< uint8_t > InputBuffer, llvm::SmallVectorImpl< uint8_t > &Uncompressed)
Definition: LZMA.cpp:28
lldb_private::lzma::getUncompressedSize
llvm::Expected< uint64_t > getUncompressedSize(llvm::ArrayRef< uint8_t > InputBuffer)
Definition: LZMA.cpp:24
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
Error
llvm::Error Error
Definition: UdtRecordCompleter.cpp:29
llvm::SmallVectorImpl
Definition: Disassembler.h:42
lldb_private::lzma::isAvailable
bool isAvailable()
Definition: LZMA.cpp:22
UINT64_MAX
#define UINT64_MAX
Definition: lldb-defines.h:35