xref: /aosp_15_r20/system/unwinding/libunwindstack/MemoryXz.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
1*eb293b8fSAndroid Build Coastguard Worker /*
2*eb293b8fSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*eb293b8fSAndroid Build Coastguard Worker  *
4*eb293b8fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*eb293b8fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*eb293b8fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*eb293b8fSAndroid Build Coastguard Worker  *
8*eb293b8fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*eb293b8fSAndroid Build Coastguard Worker  *
10*eb293b8fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*eb293b8fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*eb293b8fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*eb293b8fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*eb293b8fSAndroid Build Coastguard Worker  * limitations under the License.
15*eb293b8fSAndroid Build Coastguard Worker  */
16*eb293b8fSAndroid Build Coastguard Worker 
17*eb293b8fSAndroid Build Coastguard Worker #include <stdint.h>
18*eb293b8fSAndroid Build Coastguard Worker #include <stdlib.h>
19*eb293b8fSAndroid Build Coastguard Worker #include <string.h>
20*eb293b8fSAndroid Build Coastguard Worker 
21*eb293b8fSAndroid Build Coastguard Worker #include <algorithm>
22*eb293b8fSAndroid Build Coastguard Worker #include <atomic>
23*eb293b8fSAndroid Build Coastguard Worker #include <memory>
24*eb293b8fSAndroid Build Coastguard Worker #include <mutex>
25*eb293b8fSAndroid Build Coastguard Worker #include <string>
26*eb293b8fSAndroid Build Coastguard Worker #include <utility>
27*eb293b8fSAndroid Build Coastguard Worker 
28*eb293b8fSAndroid Build Coastguard Worker #include <7zCrc.h>
29*eb293b8fSAndroid Build Coastguard Worker #include <Xz.h>
30*eb293b8fSAndroid Build Coastguard Worker #include <XzCrc64.h>
31*eb293b8fSAndroid Build Coastguard Worker 
32*eb293b8fSAndroid Build Coastguard Worker #include <unwindstack/Log.h>
33*eb293b8fSAndroid Build Coastguard Worker 
34*eb293b8fSAndroid Build Coastguard Worker #include "MemoryXz.h"
35*eb293b8fSAndroid Build Coastguard Worker 
36*eb293b8fSAndroid Build Coastguard Worker namespace unwindstack {
37*eb293b8fSAndroid Build Coastguard Worker 
38*eb293b8fSAndroid Build Coastguard Worker // Statistics (used only for optional debug log messages).
39*eb293b8fSAndroid Build Coastguard Worker static constexpr bool kLogMemoryXzUsage = false;
40*eb293b8fSAndroid Build Coastguard Worker std::atomic_size_t MemoryXz::total_used_ = 0;
41*eb293b8fSAndroid Build Coastguard Worker std::atomic_size_t MemoryXz::total_size_ = 0;
42*eb293b8fSAndroid Build Coastguard Worker std::atomic_size_t MemoryXz::total_open_ = 0;
43*eb293b8fSAndroid Build Coastguard Worker 
MemoryXz(Memory * memory,uint64_t addr,uint64_t size,const std::string & name)44*eb293b8fSAndroid Build Coastguard Worker MemoryXz::MemoryXz(Memory* memory, uint64_t addr, uint64_t size, const std::string& name)
45*eb293b8fSAndroid Build Coastguard Worker     : compressed_memory_(memory), compressed_addr_(addr), compressed_size_(size), name_(name) {
46*eb293b8fSAndroid Build Coastguard Worker   total_open_ += 1;
47*eb293b8fSAndroid Build Coastguard Worker }
48*eb293b8fSAndroid Build Coastguard Worker 
Init()49*eb293b8fSAndroid Build Coastguard Worker bool MemoryXz::Init() {
50*eb293b8fSAndroid Build Coastguard Worker   static std::once_flag crc_initialized;
51*eb293b8fSAndroid Build Coastguard Worker   std::call_once(crc_initialized, []() {
52*eb293b8fSAndroid Build Coastguard Worker     CrcGenerateTable();
53*eb293b8fSAndroid Build Coastguard Worker     Crc64GenerateTable();
54*eb293b8fSAndroid Build Coastguard Worker   });
55*eb293b8fSAndroid Build Coastguard Worker   if (compressed_size_ >= kMaxCompressedSize) {
56*eb293b8fSAndroid Build Coastguard Worker     return false;
57*eb293b8fSAndroid Build Coastguard Worker   }
58*eb293b8fSAndroid Build Coastguard Worker   if (!ReadBlocks()) {
59*eb293b8fSAndroid Build Coastguard Worker     return false;
60*eb293b8fSAndroid Build Coastguard Worker   }
61*eb293b8fSAndroid Build Coastguard Worker 
62*eb293b8fSAndroid Build Coastguard Worker   // All blocks (except the last one) must have the same power-of-2 size.
63*eb293b8fSAndroid Build Coastguard Worker   if (blocks_.size() > 1) {
64*eb293b8fSAndroid Build Coastguard Worker     size_t block_size_log2 = __builtin_ctz(blocks_.front().decompressed_size);
65*eb293b8fSAndroid Build Coastguard Worker     auto correct_size = [=](XzBlock& b) { return b.decompressed_size == (1 << block_size_log2); };
66*eb293b8fSAndroid Build Coastguard Worker     if (std::all_of(blocks_.begin(), std::prev(blocks_.end()), correct_size) &&
67*eb293b8fSAndroid Build Coastguard Worker         blocks_.back().decompressed_size <= (1 << block_size_log2)) {
68*eb293b8fSAndroid Build Coastguard Worker       block_size_log2_ = block_size_log2;
69*eb293b8fSAndroid Build Coastguard Worker     } else {
70*eb293b8fSAndroid Build Coastguard Worker       // Inconsistent block-sizes.  Decompress and merge everything now.
71*eb293b8fSAndroid Build Coastguard Worker       std::unique_ptr<uint8_t[]> data(new uint8_t[size_]);
72*eb293b8fSAndroid Build Coastguard Worker       size_t offset = 0;
73*eb293b8fSAndroid Build Coastguard Worker       for (XzBlock& block : blocks_) {
74*eb293b8fSAndroid Build Coastguard Worker         if (!Decompress(&block)) {
75*eb293b8fSAndroid Build Coastguard Worker           return false;
76*eb293b8fSAndroid Build Coastguard Worker         }
77*eb293b8fSAndroid Build Coastguard Worker         memcpy(data.get() + offset, block.decompressed_data.get(), block.decompressed_size);
78*eb293b8fSAndroid Build Coastguard Worker         offset += block.decompressed_size;
79*eb293b8fSAndroid Build Coastguard Worker       }
80*eb293b8fSAndroid Build Coastguard Worker       blocks_.clear();
81*eb293b8fSAndroid Build Coastguard Worker       blocks_.push_back(XzBlock{
82*eb293b8fSAndroid Build Coastguard Worker           .decompressed_data = std::move(data),
83*eb293b8fSAndroid Build Coastguard Worker           .decompressed_size = size_,
84*eb293b8fSAndroid Build Coastguard Worker       });
85*eb293b8fSAndroid Build Coastguard Worker       block_size_log2_ = 31;  // Because 32 bits is too big (shift right by 32 is not allowed).
86*eb293b8fSAndroid Build Coastguard Worker     }
87*eb293b8fSAndroid Build Coastguard Worker   }
88*eb293b8fSAndroid Build Coastguard Worker 
89*eb293b8fSAndroid Build Coastguard Worker   return true;
90*eb293b8fSAndroid Build Coastguard Worker }
91*eb293b8fSAndroid Build Coastguard Worker 
~MemoryXz()92*eb293b8fSAndroid Build Coastguard Worker MemoryXz::~MemoryXz() {
93*eb293b8fSAndroid Build Coastguard Worker   total_used_ -= used_;
94*eb293b8fSAndroid Build Coastguard Worker   total_size_ -= size_;
95*eb293b8fSAndroid Build Coastguard Worker   total_open_ -= 1;
96*eb293b8fSAndroid Build Coastguard Worker }
97*eb293b8fSAndroid Build Coastguard Worker 
Read(uint64_t addr,void * buffer,size_t size)98*eb293b8fSAndroid Build Coastguard Worker size_t MemoryXz::Read(uint64_t addr, void* buffer, size_t size) {
99*eb293b8fSAndroid Build Coastguard Worker   if (addr >= size_) {
100*eb293b8fSAndroid Build Coastguard Worker     return 0;  // Read past the end.
101*eb293b8fSAndroid Build Coastguard Worker   }
102*eb293b8fSAndroid Build Coastguard Worker   uint8_t* dst = reinterpret_cast<uint8_t*>(buffer);  // Position in the output buffer.
103*eb293b8fSAndroid Build Coastguard Worker   for (size_t i = addr >> block_size_log2_; i < blocks_.size(); i++) {
104*eb293b8fSAndroid Build Coastguard Worker     XzBlock* block = &blocks_[i];
105*eb293b8fSAndroid Build Coastguard Worker     if (block->decompressed_data == nullptr) {
106*eb293b8fSAndroid Build Coastguard Worker       if (!Decompress(block)) {
107*eb293b8fSAndroid Build Coastguard Worker         break;
108*eb293b8fSAndroid Build Coastguard Worker       }
109*eb293b8fSAndroid Build Coastguard Worker     }
110*eb293b8fSAndroid Build Coastguard Worker     size_t offset = (addr - (i << block_size_log2_));  // Start inside the block.
111*eb293b8fSAndroid Build Coastguard Worker     size_t copy_bytes = std::min<size_t>(size, block->decompressed_size - offset);
112*eb293b8fSAndroid Build Coastguard Worker     memcpy(dst, block->decompressed_data.get() + offset, copy_bytes);
113*eb293b8fSAndroid Build Coastguard Worker     dst += copy_bytes;
114*eb293b8fSAndroid Build Coastguard Worker     addr += copy_bytes;
115*eb293b8fSAndroid Build Coastguard Worker     size -= copy_bytes;
116*eb293b8fSAndroid Build Coastguard Worker     if (size == 0) {
117*eb293b8fSAndroid Build Coastguard Worker       break;
118*eb293b8fSAndroid Build Coastguard Worker     }
119*eb293b8fSAndroid Build Coastguard Worker   }
120*eb293b8fSAndroid Build Coastguard Worker   return dst - reinterpret_cast<uint8_t*>(buffer);
121*eb293b8fSAndroid Build Coastguard Worker }
122*eb293b8fSAndroid Build Coastguard Worker 
ReadBlocks()123*eb293b8fSAndroid Build Coastguard Worker bool MemoryXz::ReadBlocks() {
124*eb293b8fSAndroid Build Coastguard Worker   static ISzAlloc alloc;
125*eb293b8fSAndroid Build Coastguard Worker   alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
126*eb293b8fSAndroid Build Coastguard Worker   alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
127*eb293b8fSAndroid Build Coastguard Worker 
128*eb293b8fSAndroid Build Coastguard Worker   // Read the compressed data, so we can quickly scan through the headers.
129*eb293b8fSAndroid Build Coastguard Worker   std::unique_ptr<uint8_t[]> compressed_data(new (std::nothrow) uint8_t[compressed_size_]);
130*eb293b8fSAndroid Build Coastguard Worker   if (compressed_data.get() == nullptr) {
131*eb293b8fSAndroid Build Coastguard Worker     return false;
132*eb293b8fSAndroid Build Coastguard Worker   }
133*eb293b8fSAndroid Build Coastguard Worker   if (!compressed_memory_->ReadFully(compressed_addr_, compressed_data.get(), compressed_size_)) {
134*eb293b8fSAndroid Build Coastguard Worker     return false;
135*eb293b8fSAndroid Build Coastguard Worker   }
136*eb293b8fSAndroid Build Coastguard Worker 
137*eb293b8fSAndroid Build Coastguard Worker   // Implement the required interface for communication
138*eb293b8fSAndroid Build Coastguard Worker   // (written in C so we can not use virtual methods or member functions).
139*eb293b8fSAndroid Build Coastguard Worker   struct XzLookInStream : public ILookInStream, public ICompressProgress {
140*eb293b8fSAndroid Build Coastguard Worker     static SRes LookImpl(const ILookInStream* p, const void** buf, size_t* size) {
141*eb293b8fSAndroid Build Coastguard Worker       auto* ctx = reinterpret_cast<const XzLookInStream*>(p);
142*eb293b8fSAndroid Build Coastguard Worker       *buf = ctx->data + ctx->offset;
143*eb293b8fSAndroid Build Coastguard Worker       *size = std::min(*size, ctx->size - ctx->offset);
144*eb293b8fSAndroid Build Coastguard Worker       return SZ_OK;
145*eb293b8fSAndroid Build Coastguard Worker     }
146*eb293b8fSAndroid Build Coastguard Worker     static SRes SkipImpl(const ILookInStream* p, size_t len) {
147*eb293b8fSAndroid Build Coastguard Worker       auto* ctx = reinterpret_cast<XzLookInStream*>(const_cast<ILookInStream*>(p));
148*eb293b8fSAndroid Build Coastguard Worker       ctx->offset += len;
149*eb293b8fSAndroid Build Coastguard Worker       return SZ_OK;
150*eb293b8fSAndroid Build Coastguard Worker     }
151*eb293b8fSAndroid Build Coastguard Worker     static SRes ReadImpl(const ILookInStream* p, void* buf, size_t* size) {
152*eb293b8fSAndroid Build Coastguard Worker       auto* ctx = reinterpret_cast<const XzLookInStream*>(p);
153*eb293b8fSAndroid Build Coastguard Worker       *size = std::min(*size, ctx->size - ctx->offset);
154*eb293b8fSAndroid Build Coastguard Worker       memcpy(buf, ctx->data + ctx->offset, *size);
155*eb293b8fSAndroid Build Coastguard Worker       return SZ_OK;
156*eb293b8fSAndroid Build Coastguard Worker     }
157*eb293b8fSAndroid Build Coastguard Worker     static SRes SeekImpl(const ILookInStream* p, Int64* pos, ESzSeek origin) {
158*eb293b8fSAndroid Build Coastguard Worker       auto* ctx = reinterpret_cast<XzLookInStream*>(const_cast<ILookInStream*>(p));
159*eb293b8fSAndroid Build Coastguard Worker       switch (origin) {
160*eb293b8fSAndroid Build Coastguard Worker         case SZ_SEEK_SET:
161*eb293b8fSAndroid Build Coastguard Worker           ctx->offset = *pos;
162*eb293b8fSAndroid Build Coastguard Worker           break;
163*eb293b8fSAndroid Build Coastguard Worker         case SZ_SEEK_CUR:
164*eb293b8fSAndroid Build Coastguard Worker           ctx->offset += *pos;
165*eb293b8fSAndroid Build Coastguard Worker           break;
166*eb293b8fSAndroid Build Coastguard Worker         case SZ_SEEK_END:
167*eb293b8fSAndroid Build Coastguard Worker           ctx->offset = ctx->size + *pos;
168*eb293b8fSAndroid Build Coastguard Worker           break;
169*eb293b8fSAndroid Build Coastguard Worker       }
170*eb293b8fSAndroid Build Coastguard Worker       *pos = ctx->offset;
171*eb293b8fSAndroid Build Coastguard Worker       return SZ_OK;
172*eb293b8fSAndroid Build Coastguard Worker     }
173*eb293b8fSAndroid Build Coastguard Worker     static SRes ProgressImpl(const ICompressProgress*, UInt64, UInt64) { return SZ_OK; }
174*eb293b8fSAndroid Build Coastguard Worker     size_t offset;
175*eb293b8fSAndroid Build Coastguard Worker     uint8_t* data;
176*eb293b8fSAndroid Build Coastguard Worker     size_t size;
177*eb293b8fSAndroid Build Coastguard Worker   };
178*eb293b8fSAndroid Build Coastguard Worker   XzLookInStream callbacks;
179*eb293b8fSAndroid Build Coastguard Worker   callbacks.Look = &XzLookInStream::LookImpl;
180*eb293b8fSAndroid Build Coastguard Worker   callbacks.Skip = &XzLookInStream::SkipImpl;
181*eb293b8fSAndroid Build Coastguard Worker   callbacks.Read = &XzLookInStream::ReadImpl;
182*eb293b8fSAndroid Build Coastguard Worker   callbacks.Seek = &XzLookInStream::SeekImpl;
183*eb293b8fSAndroid Build Coastguard Worker   callbacks.Progress = &XzLookInStream::ProgressImpl;
184*eb293b8fSAndroid Build Coastguard Worker   callbacks.offset = 0;
185*eb293b8fSAndroid Build Coastguard Worker   callbacks.data = compressed_data.get();
186*eb293b8fSAndroid Build Coastguard Worker   callbacks.size = compressed_size_;
187*eb293b8fSAndroid Build Coastguard Worker 
188*eb293b8fSAndroid Build Coastguard Worker   // Iterate over the internal XZ blocks without decompressing them.
189*eb293b8fSAndroid Build Coastguard Worker   CXzs xzs;
190*eb293b8fSAndroid Build Coastguard Worker   Xzs_Construct(&xzs);
191*eb293b8fSAndroid Build Coastguard Worker   Int64 end_offset = compressed_size_;
192*eb293b8fSAndroid Build Coastguard Worker   if (Xzs_ReadBackward(&xzs, &callbacks, &end_offset, &callbacks, &alloc) == SZ_OK) {
193*eb293b8fSAndroid Build Coastguard Worker     blocks_.reserve(Xzs_GetNumBlocks(&xzs));
194*eb293b8fSAndroid Build Coastguard Worker     size_t dst_offset = 0;
195*eb293b8fSAndroid Build Coastguard Worker     for (int s = xzs.num - 1; s >= 0; s--) {
196*eb293b8fSAndroid Build Coastguard Worker       const CXzStream& stream = xzs.streams[s];
197*eb293b8fSAndroid Build Coastguard Worker       size_t src_offset = stream.startOffset + XZ_STREAM_HEADER_SIZE;
198*eb293b8fSAndroid Build Coastguard Worker       for (size_t b = 0; b < stream.numBlocks; b++) {
199*eb293b8fSAndroid Build Coastguard Worker         const CXzBlockSizes& block = stream.blocks[b];
200*eb293b8fSAndroid Build Coastguard Worker         blocks_.push_back(XzBlock{
201*eb293b8fSAndroid Build Coastguard Worker             .decompressed_data = nullptr,  // Lazy allocation and decompression.
202*eb293b8fSAndroid Build Coastguard Worker             .decompressed_size = static_cast<uint32_t>(block.unpackSize),
203*eb293b8fSAndroid Build Coastguard Worker             .compressed_offset = static_cast<uint32_t>(src_offset),
204*eb293b8fSAndroid Build Coastguard Worker             .compressed_size = static_cast<uint32_t>((block.totalSize + 3) & ~3u),
205*eb293b8fSAndroid Build Coastguard Worker             .stream_flags = stream.flags,
206*eb293b8fSAndroid Build Coastguard Worker         });
207*eb293b8fSAndroid Build Coastguard Worker         dst_offset += blocks_.back().decompressed_size;
208*eb293b8fSAndroid Build Coastguard Worker         src_offset += blocks_.back().compressed_size;
209*eb293b8fSAndroid Build Coastguard Worker       }
210*eb293b8fSAndroid Build Coastguard Worker     }
211*eb293b8fSAndroid Build Coastguard Worker     size_ = dst_offset;
212*eb293b8fSAndroid Build Coastguard Worker     total_size_ += dst_offset;
213*eb293b8fSAndroid Build Coastguard Worker   }
214*eb293b8fSAndroid Build Coastguard Worker   Xzs_Free(&xzs, &alloc);
215*eb293b8fSAndroid Build Coastguard Worker   return !blocks_.empty();
216*eb293b8fSAndroid Build Coastguard Worker }
217*eb293b8fSAndroid Build Coastguard Worker 
Decompress(XzBlock * block)218*eb293b8fSAndroid Build Coastguard Worker bool MemoryXz::Decompress(XzBlock* block) {
219*eb293b8fSAndroid Build Coastguard Worker   static ISzAlloc alloc;
220*eb293b8fSAndroid Build Coastguard Worker   alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
221*eb293b8fSAndroid Build Coastguard Worker   alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
222*eb293b8fSAndroid Build Coastguard Worker 
223*eb293b8fSAndroid Build Coastguard Worker   // Read the compressed data for this block.
224*eb293b8fSAndroid Build Coastguard Worker   std::unique_ptr<uint8_t[]> compressed_data(new (std::nothrow) uint8_t[block->compressed_size]);
225*eb293b8fSAndroid Build Coastguard Worker   if (compressed_data.get() == nullptr) {
226*eb293b8fSAndroid Build Coastguard Worker     return false;
227*eb293b8fSAndroid Build Coastguard Worker   }
228*eb293b8fSAndroid Build Coastguard Worker   if (!compressed_memory_->ReadFully(compressed_addr_ + block->compressed_offset,
229*eb293b8fSAndroid Build Coastguard Worker                                      compressed_data.get(), block->compressed_size)) {
230*eb293b8fSAndroid Build Coastguard Worker     return false;
231*eb293b8fSAndroid Build Coastguard Worker   }
232*eb293b8fSAndroid Build Coastguard Worker 
233*eb293b8fSAndroid Build Coastguard Worker   // Allocate decompressed memory.
234*eb293b8fSAndroid Build Coastguard Worker   std::unique_ptr<uint8_t[]> decompressed_data(new uint8_t[block->decompressed_size]);
235*eb293b8fSAndroid Build Coastguard Worker   if (decompressed_data == nullptr) {
236*eb293b8fSAndroid Build Coastguard Worker     return false;
237*eb293b8fSAndroid Build Coastguard Worker   }
238*eb293b8fSAndroid Build Coastguard Worker 
239*eb293b8fSAndroid Build Coastguard Worker   // Decompress.
240*eb293b8fSAndroid Build Coastguard Worker   CXzUnpacker state{};
241*eb293b8fSAndroid Build Coastguard Worker   XzUnpacker_Construct(&state, &alloc);
242*eb293b8fSAndroid Build Coastguard Worker   state.streamFlags = block->stream_flags;
243*eb293b8fSAndroid Build Coastguard Worker   XzUnpacker_PrepareToRandomBlockDecoding(&state);
244*eb293b8fSAndroid Build Coastguard Worker   size_t decompressed_size = block->decompressed_size;
245*eb293b8fSAndroid Build Coastguard Worker   size_t compressed_size = block->compressed_size;
246*eb293b8fSAndroid Build Coastguard Worker   ECoderStatus status;
247*eb293b8fSAndroid Build Coastguard Worker   XzUnpacker_SetOutBuf(&state, decompressed_data.get(), decompressed_size);
248*eb293b8fSAndroid Build Coastguard Worker   int return_val =
249*eb293b8fSAndroid Build Coastguard Worker       XzUnpacker_Code(&state, /*decompressed_data=*/nullptr, &decompressed_size,
250*eb293b8fSAndroid Build Coastguard Worker                       compressed_data.get(), &compressed_size, true, CODER_FINISH_END, &status);
251*eb293b8fSAndroid Build Coastguard Worker   XzUnpacker_Free(&state);
252*eb293b8fSAndroid Build Coastguard Worker   if (return_val != SZ_OK || status != CODER_STATUS_FINISHED_WITH_MARK) {
253*eb293b8fSAndroid Build Coastguard Worker     Log::Error("Cannot decompress \"%s\"", name_.c_str());
254*eb293b8fSAndroid Build Coastguard Worker     return false;
255*eb293b8fSAndroid Build Coastguard Worker   }
256*eb293b8fSAndroid Build Coastguard Worker 
257*eb293b8fSAndroid Build Coastguard Worker   used_ += block->decompressed_size;
258*eb293b8fSAndroid Build Coastguard Worker   total_used_ += block->decompressed_size;
259*eb293b8fSAndroid Build Coastguard Worker   if (kLogMemoryXzUsage) {
260*eb293b8fSAndroid Build Coastguard Worker     Log::Info("decompressed memory: %zi%% of %ziKB (%zi files), %i%% of %iKB (%s)",
261*eb293b8fSAndroid Build Coastguard Worker               100 * total_used_ / total_size_, total_size_ / 1024, total_open_.load(),
262*eb293b8fSAndroid Build Coastguard Worker               100 * used_ / size_, size_ / 1024, name_.c_str());
263*eb293b8fSAndroid Build Coastguard Worker   }
264*eb293b8fSAndroid Build Coastguard Worker 
265*eb293b8fSAndroid Build Coastguard Worker   block->decompressed_data = std::move(decompressed_data);
266*eb293b8fSAndroid Build Coastguard Worker   return true;
267*eb293b8fSAndroid Build Coastguard Worker }
268*eb293b8fSAndroid Build Coastguard Worker 
269*eb293b8fSAndroid Build Coastguard Worker }  // namespace unwindstack
270