xref: /aosp_15_r20/art/runtime/oat/image.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "image.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <lz4.h>
20*795d594fSAndroid Build Coastguard Worker #include <lz4hc.h>
21*795d594fSAndroid Build Coastguard Worker #include <sstream>
22*795d594fSAndroid Build Coastguard Worker #include <sys/stat.h>
23*795d594fSAndroid Build Coastguard Worker #include <zlib.h>
24*795d594fSAndroid Build Coastguard Worker 
25*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/length_prefixed_array.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
30*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "mirror/object_array-inl.h"
32*795d594fSAndroid Build Coastguard Worker #include "mirror/object_array.h"
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
37*795d594fSAndroid Build Coastguard Worker // Revert dex cache change.
38*795d594fSAndroid Build Coastguard Worker const uint8_t ImageHeader::kImageVersion[] = { '1', '1', '8', '\0' };
39*795d594fSAndroid Build Coastguard Worker 
ImageHeader(uint32_t image_reservation_size,uint32_t component_count,uint32_t image_begin,uint32_t image_size,ImageSection * sections,uint32_t image_roots,uint32_t oat_checksum,uint32_t oat_file_begin,uint32_t oat_data_begin,uint32_t oat_data_end,uint32_t oat_file_end,uint32_t boot_image_begin,uint32_t boot_image_size,uint32_t boot_image_component_count,uint32_t boot_image_checksum,PointerSize pointer_size)40*795d594fSAndroid Build Coastguard Worker ImageHeader::ImageHeader(uint32_t image_reservation_size,
41*795d594fSAndroid Build Coastguard Worker                          uint32_t component_count,
42*795d594fSAndroid Build Coastguard Worker                          uint32_t image_begin,
43*795d594fSAndroid Build Coastguard Worker                          uint32_t image_size,
44*795d594fSAndroid Build Coastguard Worker                          ImageSection* sections,
45*795d594fSAndroid Build Coastguard Worker                          uint32_t image_roots,
46*795d594fSAndroid Build Coastguard Worker                          uint32_t oat_checksum,
47*795d594fSAndroid Build Coastguard Worker                          uint32_t oat_file_begin,
48*795d594fSAndroid Build Coastguard Worker                          uint32_t oat_data_begin,
49*795d594fSAndroid Build Coastguard Worker                          uint32_t oat_data_end,
50*795d594fSAndroid Build Coastguard Worker                          uint32_t oat_file_end,
51*795d594fSAndroid Build Coastguard Worker                          uint32_t boot_image_begin,
52*795d594fSAndroid Build Coastguard Worker                          uint32_t boot_image_size,
53*795d594fSAndroid Build Coastguard Worker                          uint32_t boot_image_component_count,
54*795d594fSAndroid Build Coastguard Worker                          uint32_t boot_image_checksum,
55*795d594fSAndroid Build Coastguard Worker                          PointerSize pointer_size)
56*795d594fSAndroid Build Coastguard Worker   : image_reservation_size_(image_reservation_size),
57*795d594fSAndroid Build Coastguard Worker     component_count_(component_count),
58*795d594fSAndroid Build Coastguard Worker     image_begin_(image_begin),
59*795d594fSAndroid Build Coastguard Worker     image_size_(image_size),
60*795d594fSAndroid Build Coastguard Worker     image_checksum_(0u),
61*795d594fSAndroid Build Coastguard Worker     oat_checksum_(oat_checksum),
62*795d594fSAndroid Build Coastguard Worker     oat_file_begin_(oat_file_begin),
63*795d594fSAndroid Build Coastguard Worker     oat_data_begin_(oat_data_begin),
64*795d594fSAndroid Build Coastguard Worker     oat_data_end_(oat_data_end),
65*795d594fSAndroid Build Coastguard Worker     oat_file_end_(oat_file_end),
66*795d594fSAndroid Build Coastguard Worker     boot_image_begin_(boot_image_begin),
67*795d594fSAndroid Build Coastguard Worker     boot_image_size_(boot_image_size),
68*795d594fSAndroid Build Coastguard Worker     boot_image_component_count_(boot_image_component_count),
69*795d594fSAndroid Build Coastguard Worker     boot_image_checksum_(boot_image_checksum),
70*795d594fSAndroid Build Coastguard Worker     image_roots_(image_roots),
71*795d594fSAndroid Build Coastguard Worker     pointer_size_(pointer_size) {
72*795d594fSAndroid Build Coastguard Worker   CHECK_EQ(image_begin, RoundUp(image_begin, kElfSegmentAlignment));
73*795d594fSAndroid Build Coastguard Worker   if (oat_checksum != 0u) {
74*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kElfSegmentAlignment));
75*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(oat_data_begin, RoundUp(oat_data_begin, kElfSegmentAlignment));
76*795d594fSAndroid Build Coastguard Worker     CHECK_LT(image_roots, oat_file_begin);
77*795d594fSAndroid Build Coastguard Worker     CHECK_LE(oat_file_begin, oat_data_begin);
78*795d594fSAndroid Build Coastguard Worker     CHECK_LT(oat_data_begin, oat_data_end);
79*795d594fSAndroid Build Coastguard Worker     CHECK_LE(oat_data_end, oat_file_end);
80*795d594fSAndroid Build Coastguard Worker   }
81*795d594fSAndroid Build Coastguard Worker   static_assert(sizeof(PointerSize) == sizeof(uint32_t),
82*795d594fSAndroid Build Coastguard Worker                 "PointerSize class is expected to be a uint32_t for the header");
83*795d594fSAndroid Build Coastguard Worker   memcpy(magic_, kImageMagic, sizeof(kImageMagic));
84*795d594fSAndroid Build Coastguard Worker   memcpy(version_, kImageVersion, sizeof(kImageVersion));
85*795d594fSAndroid Build Coastguard Worker   std::copy_n(sections, kSectionCount, sections_);
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker 
RelocateImageReferences(int64_t delta)88*795d594fSAndroid Build Coastguard Worker void ImageHeader::RelocateImageReferences(int64_t delta) {
89*795d594fSAndroid Build Coastguard Worker   // App Images can be relocated to a page aligned address.
90*795d594fSAndroid Build Coastguard Worker   // Unlike with the Boot Image, for which the memory is reserved in advance of
91*795d594fSAndroid Build Coastguard Worker   // loading and is aligned to kElfSegmentAlignment, the App Images can be mapped
92*795d594fSAndroid Build Coastguard Worker   // without reserving memory i.e. via direct file mapping in which case the
93*795d594fSAndroid Build Coastguard Worker   // memory range is aligned by the kernel and the only guarantee is that it is
94*795d594fSAndroid Build Coastguard Worker   // aligned to the page sizes.
95*795d594fSAndroid Build Coastguard Worker   //
96*795d594fSAndroid Build Coastguard Worker   // NOTE: While this might be less than alignment required via information in
97*795d594fSAndroid Build Coastguard Worker   //       the ELF header, it should be sufficient in practice as the only reason
98*795d594fSAndroid Build Coastguard Worker   //       for the ELF segment alignment to be more than one page size is the
99*795d594fSAndroid Build Coastguard Worker   //       compatibility of the ELF with system configurations that use larger
100*795d594fSAndroid Build Coastguard Worker   //       page size.
101*795d594fSAndroid Build Coastguard Worker   //
102*795d594fSAndroid Build Coastguard Worker   //       Adding preliminary memory reservation would introduce certain overhead.
103*795d594fSAndroid Build Coastguard Worker   //
104*795d594fSAndroid Build Coastguard Worker   //       However, technically the alignment requirement isn't fulfilled and that
105*795d594fSAndroid Build Coastguard Worker   //       might be worth addressing even if it adds certain overhead. This will have
106*795d594fSAndroid Build Coastguard Worker   //       to be done in alignment with the dynamic linker's ELF loader as
107*795d594fSAndroid Build Coastguard Worker   //       otherwise inconsistency would still be possible e.g. when using
108*795d594fSAndroid Build Coastguard Worker   //       `dlopen`-like calls to load OAT files.
109*795d594fSAndroid Build Coastguard Worker   CHECK_ALIGNED_PARAM(delta, gPageSize) << "relocation delta must be page aligned";
110*795d594fSAndroid Build Coastguard Worker   oat_file_begin_ += delta;
111*795d594fSAndroid Build Coastguard Worker   oat_data_begin_ += delta;
112*795d594fSAndroid Build Coastguard Worker   oat_data_end_ += delta;
113*795d594fSAndroid Build Coastguard Worker   oat_file_end_ += delta;
114*795d594fSAndroid Build Coastguard Worker   image_begin_ += delta;
115*795d594fSAndroid Build Coastguard Worker   image_roots_ += delta;
116*795d594fSAndroid Build Coastguard Worker }
117*795d594fSAndroid Build Coastguard Worker 
RelocateBootImageReferences(int64_t delta)118*795d594fSAndroid Build Coastguard Worker void ImageHeader::RelocateBootImageReferences(int64_t delta) {
119*795d594fSAndroid Build Coastguard Worker   CHECK_ALIGNED(delta, kElfSegmentAlignment) << "relocation delta must be Elf segment aligned";
120*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(boot_image_begin_ != 0u, boot_image_size_ != 0u);
121*795d594fSAndroid Build Coastguard Worker   if (boot_image_begin_ != 0u) {
122*795d594fSAndroid Build Coastguard Worker     boot_image_begin_ += delta;
123*795d594fSAndroid Build Coastguard Worker   }
124*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < kImageMethodsCount; ++i) {
125*795d594fSAndroid Build Coastguard Worker     image_methods_[i] += delta;
126*795d594fSAndroid Build Coastguard Worker   }
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker 
IsAppImage() const129*795d594fSAndroid Build Coastguard Worker bool ImageHeader::IsAppImage() const {
130*795d594fSAndroid Build Coastguard Worker   // Unlike boot image and boot image extensions which include address space for
131*795d594fSAndroid Build Coastguard Worker   // oat files in their reservation size, app images are loaded separately from oat
132*795d594fSAndroid Build Coastguard Worker   // files and their reservation size is the image size rounded up to Elf alignment.
133*795d594fSAndroid Build Coastguard Worker   return image_reservation_size_ == RoundUp(image_size_, kElfSegmentAlignment);
134*795d594fSAndroid Build Coastguard Worker }
135*795d594fSAndroid Build Coastguard Worker 
GetImageSpaceCount() const136*795d594fSAndroid Build Coastguard Worker uint32_t ImageHeader::GetImageSpaceCount() const {
137*795d594fSAndroid Build Coastguard Worker   DCHECK(!IsAppImage());
138*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(component_count_, 0u);  // Must be the header for the first component.
139*795d594fSAndroid Build Coastguard Worker   // For images compiled with --single-image, there is only one oat file. To detect
140*795d594fSAndroid Build Coastguard Worker   // that, check whether the reservation ends at the end of the first oat file.
141*795d594fSAndroid Build Coastguard Worker   return (image_begin_ + image_reservation_size_ == oat_file_end_) ? 1u : component_count_;
142*795d594fSAndroid Build Coastguard Worker }
143*795d594fSAndroid Build Coastguard Worker 
IsValid() const144*795d594fSAndroid Build Coastguard Worker bool ImageHeader::IsValid() const {
145*795d594fSAndroid Build Coastguard Worker   if (memcmp(magic_, kImageMagic, sizeof(kImageMagic)) != 0) {
146*795d594fSAndroid Build Coastguard Worker     return false;
147*795d594fSAndroid Build Coastguard Worker   }
148*795d594fSAndroid Build Coastguard Worker   if (memcmp(version_, kImageVersion, sizeof(kImageVersion)) != 0) {
149*795d594fSAndroid Build Coastguard Worker     return false;
150*795d594fSAndroid Build Coastguard Worker   }
151*795d594fSAndroid Build Coastguard Worker   if (!IsAligned<kElfSegmentAlignment>(image_reservation_size_)) {
152*795d594fSAndroid Build Coastguard Worker     return false;
153*795d594fSAndroid Build Coastguard Worker   }
154*795d594fSAndroid Build Coastguard Worker   // Unsigned so wraparound is well defined.
155*795d594fSAndroid Build Coastguard Worker   if (image_begin_ >= image_begin_ + image_size_) {
156*795d594fSAndroid Build Coastguard Worker     return false;
157*795d594fSAndroid Build Coastguard Worker   }
158*795d594fSAndroid Build Coastguard Worker   if (oat_checksum_ != 0u) {
159*795d594fSAndroid Build Coastguard Worker     if (oat_file_begin_ > oat_file_end_) {
160*795d594fSAndroid Build Coastguard Worker       return false;
161*795d594fSAndroid Build Coastguard Worker     }
162*795d594fSAndroid Build Coastguard Worker     if (oat_data_begin_ > oat_data_end_) {
163*795d594fSAndroid Build Coastguard Worker       return false;
164*795d594fSAndroid Build Coastguard Worker     }
165*795d594fSAndroid Build Coastguard Worker     if (oat_file_begin_ >= oat_data_begin_) {
166*795d594fSAndroid Build Coastguard Worker       return false;
167*795d594fSAndroid Build Coastguard Worker     }
168*795d594fSAndroid Build Coastguard Worker   }
169*795d594fSAndroid Build Coastguard Worker   return true;
170*795d594fSAndroid Build Coastguard Worker }
171*795d594fSAndroid Build Coastguard Worker 
GetMagic() const172*795d594fSAndroid Build Coastguard Worker const char* ImageHeader::GetMagic() const {
173*795d594fSAndroid Build Coastguard Worker   CHECK(IsValid());
174*795d594fSAndroid Build Coastguard Worker   return reinterpret_cast<const char*>(magic_);
175*795d594fSAndroid Build Coastguard Worker }
176*795d594fSAndroid Build Coastguard Worker 
GetImageMethod(ImageMethod index) const177*795d594fSAndroid Build Coastguard Worker ArtMethod* ImageHeader::GetImageMethod(ImageMethod index) const {
178*795d594fSAndroid Build Coastguard Worker   CHECK_LT(static_cast<size_t>(index), kImageMethodsCount);
179*795d594fSAndroid Build Coastguard Worker   return reinterpret_cast<ArtMethod*>(image_methods_[index]);
180*795d594fSAndroid Build Coastguard Worker }
181*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const ImageSection & section)182*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const ImageSection& section) {
183*795d594fSAndroid Build Coastguard Worker   return os << "size=" << section.Size() << " range=" << section.Offset() << "-" << section.End();
184*795d594fSAndroid Build Coastguard Worker }
185*795d594fSAndroid Build Coastguard Worker 
VisitObjects(ObjectVisitor * visitor,uint8_t * base,PointerSize pointer_size) const186*795d594fSAndroid Build Coastguard Worker void ImageHeader::VisitObjects(ObjectVisitor* visitor,
187*795d594fSAndroid Build Coastguard Worker                                uint8_t* base,
188*795d594fSAndroid Build Coastguard Worker                                PointerSize pointer_size) const {
189*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(pointer_size, GetPointerSize());
190*795d594fSAndroid Build Coastguard Worker   const ImageSection& objects = GetObjectsSection();
191*795d594fSAndroid Build Coastguard Worker   static const size_t kStartPos = RoundUp(sizeof(ImageHeader), kObjectAlignment);
192*795d594fSAndroid Build Coastguard Worker   for (size_t pos = kStartPos; pos < objects.Size(); ) {
193*795d594fSAndroid Build Coastguard Worker     mirror::Object* object = reinterpret_cast<mirror::Object*>(base + objects.Offset() + pos);
194*795d594fSAndroid Build Coastguard Worker     visitor->Visit(object);
195*795d594fSAndroid Build Coastguard Worker     pos += RoundUp(object->SizeOf(), kObjectAlignment);
196*795d594fSAndroid Build Coastguard Worker   }
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker 
GetPointerSize() const199*795d594fSAndroid Build Coastguard Worker PointerSize ImageHeader::GetPointerSize() const {
200*795d594fSAndroid Build Coastguard Worker   return pointer_size_;
201*795d594fSAndroid Build Coastguard Worker }
202*795d594fSAndroid Build Coastguard Worker 
LZ4_decompress_safe_checked(const char * source,char * dest,int compressed_size,int max_decompressed_size,size_t * decompressed_size_checked,std::string * error_msg)203*795d594fSAndroid Build Coastguard Worker bool LZ4_decompress_safe_checked(const char* source,
204*795d594fSAndroid Build Coastguard Worker                                  char* dest,
205*795d594fSAndroid Build Coastguard Worker                                  int compressed_size,
206*795d594fSAndroid Build Coastguard Worker                                  int max_decompressed_size,
207*795d594fSAndroid Build Coastguard Worker                                  /*out*/ size_t* decompressed_size_checked,
208*795d594fSAndroid Build Coastguard Worker                                  /*out*/ std::string* error_msg) {
209*795d594fSAndroid Build Coastguard Worker   int decompressed_size = LZ4_decompress_safe(source, dest, compressed_size, max_decompressed_size);
210*795d594fSAndroid Build Coastguard Worker   if (UNLIKELY(decompressed_size < 0)) {
211*795d594fSAndroid Build Coastguard Worker     *error_msg = android::base::StringPrintf("LZ4_decompress_safe() returned negative size: %d",
212*795d594fSAndroid Build Coastguard Worker                                              decompressed_size);
213*795d594fSAndroid Build Coastguard Worker     return false;
214*795d594fSAndroid Build Coastguard Worker   } else {
215*795d594fSAndroid Build Coastguard Worker     *decompressed_size_checked = static_cast<size_t>(decompressed_size);
216*795d594fSAndroid Build Coastguard Worker     return true;
217*795d594fSAndroid Build Coastguard Worker   }
218*795d594fSAndroid Build Coastguard Worker }
219*795d594fSAndroid Build Coastguard Worker 
Decompress(uint8_t * out_ptr,const uint8_t * in_ptr,std::string * error_msg) const220*795d594fSAndroid Build Coastguard Worker bool ImageHeader::Block::Decompress(uint8_t* out_ptr,
221*795d594fSAndroid Build Coastguard Worker                                     const uint8_t* in_ptr,
222*795d594fSAndroid Build Coastguard Worker                                     std::string* error_msg) const {
223*795d594fSAndroid Build Coastguard Worker   switch (storage_mode_) {
224*795d594fSAndroid Build Coastguard Worker     case kStorageModeUncompressed: {
225*795d594fSAndroid Build Coastguard Worker       CHECK_EQ(image_size_, data_size_);
226*795d594fSAndroid Build Coastguard Worker       memcpy(out_ptr + image_offset_, in_ptr + data_offset_, data_size_);
227*795d594fSAndroid Build Coastguard Worker       break;
228*795d594fSAndroid Build Coastguard Worker     }
229*795d594fSAndroid Build Coastguard Worker     case kStorageModeLZ4:
230*795d594fSAndroid Build Coastguard Worker     case kStorageModeLZ4HC: {
231*795d594fSAndroid Build Coastguard Worker       // LZ4HC and LZ4 have same internal format, both use LZ4_decompress.
232*795d594fSAndroid Build Coastguard Worker       size_t decompressed_size;
233*795d594fSAndroid Build Coastguard Worker       bool ok = LZ4_decompress_safe_checked(
234*795d594fSAndroid Build Coastguard Worker           reinterpret_cast<const char*>(in_ptr) + data_offset_,
235*795d594fSAndroid Build Coastguard Worker           reinterpret_cast<char*>(out_ptr) + image_offset_,
236*795d594fSAndroid Build Coastguard Worker           data_size_,
237*795d594fSAndroid Build Coastguard Worker           image_size_,
238*795d594fSAndroid Build Coastguard Worker           &decompressed_size,
239*795d594fSAndroid Build Coastguard Worker           error_msg);
240*795d594fSAndroid Build Coastguard Worker       if (!ok) {
241*795d594fSAndroid Build Coastguard Worker         return false;
242*795d594fSAndroid Build Coastguard Worker       }
243*795d594fSAndroid Build Coastguard Worker       if (decompressed_size != image_size_) {
244*795d594fSAndroid Build Coastguard Worker         if (error_msg != nullptr) {
245*795d594fSAndroid Build Coastguard Worker           // Maybe some disk / memory corruption, just bail.
246*795d594fSAndroid Build Coastguard Worker           *error_msg = (std::ostringstream() << "Decompressed size different than image size: "
247*795d594fSAndroid Build Coastguard Worker                                              << decompressed_size << ", and " << image_size_).str();
248*795d594fSAndroid Build Coastguard Worker         }
249*795d594fSAndroid Build Coastguard Worker         return false;
250*795d594fSAndroid Build Coastguard Worker       }
251*795d594fSAndroid Build Coastguard Worker       break;
252*795d594fSAndroid Build Coastguard Worker     }
253*795d594fSAndroid Build Coastguard Worker     default: {
254*795d594fSAndroid Build Coastguard Worker       if (error_msg != nullptr) {
255*795d594fSAndroid Build Coastguard Worker         *error_msg = (std::ostringstream() << "Invalid image format " << storage_mode_).str();
256*795d594fSAndroid Build Coastguard Worker       }
257*795d594fSAndroid Build Coastguard Worker       return false;
258*795d594fSAndroid Build Coastguard Worker     }
259*795d594fSAndroid Build Coastguard Worker   }
260*795d594fSAndroid Build Coastguard Worker   return true;
261*795d594fSAndroid Build Coastguard Worker }
262*795d594fSAndroid Build Coastguard Worker 
GetImageSectionName(ImageSections index)263*795d594fSAndroid Build Coastguard Worker const char* ImageHeader::GetImageSectionName(ImageSections index) {
264*795d594fSAndroid Build Coastguard Worker   switch (index) {
265*795d594fSAndroid Build Coastguard Worker     case kSectionObjects: return "Objects";
266*795d594fSAndroid Build Coastguard Worker     case kSectionArtFields: return "ArtFields";
267*795d594fSAndroid Build Coastguard Worker     case kSectionArtMethods: return "ArtMethods";
268*795d594fSAndroid Build Coastguard Worker     case kSectionImTables: return "ImTables";
269*795d594fSAndroid Build Coastguard Worker     case kSectionIMTConflictTables: return "IMTConflictTables";
270*795d594fSAndroid Build Coastguard Worker     case kSectionRuntimeMethods: return "RuntimeMethods";
271*795d594fSAndroid Build Coastguard Worker     case kSectionJniStubMethods: return "JniStubMethods";
272*795d594fSAndroid Build Coastguard Worker     case kSectionInternedStrings: return "InternedStrings";
273*795d594fSAndroid Build Coastguard Worker     case kSectionClassTable: return "ClassTable";
274*795d594fSAndroid Build Coastguard Worker     case kSectionStringReferenceOffsets: return "StringReferenceOffsets";
275*795d594fSAndroid Build Coastguard Worker     case kSectionDexCacheArrays: return "DexCacheArrays";
276*795d594fSAndroid Build Coastguard Worker     case kSectionMetadata: return "Metadata";
277*795d594fSAndroid Build Coastguard Worker     case kSectionImageBitmap: return "ImageBitmap";
278*795d594fSAndroid Build Coastguard Worker     case kSectionCount: return nullptr;
279*795d594fSAndroid Build Coastguard Worker   }
280*795d594fSAndroid Build Coastguard Worker }
281*795d594fSAndroid Build Coastguard Worker 
282*795d594fSAndroid Build Coastguard Worker // Compress data from `source` into `storage`.
CompressData(ArrayRef<const uint8_t> source,ImageHeader::StorageMode image_storage_mode,dchecked_vector<uint8_t> * storage)283*795d594fSAndroid Build Coastguard Worker static bool CompressData(ArrayRef<const uint8_t> source,
284*795d594fSAndroid Build Coastguard Worker                          ImageHeader::StorageMode image_storage_mode,
285*795d594fSAndroid Build Coastguard Worker                          /*out*/ dchecked_vector<uint8_t>* storage) {
286*795d594fSAndroid Build Coastguard Worker   const uint64_t compress_start_time = NanoTime();
287*795d594fSAndroid Build Coastguard Worker 
288*795d594fSAndroid Build Coastguard Worker   // Bound is same for both LZ4 and LZ4HC.
289*795d594fSAndroid Build Coastguard Worker   storage->resize(LZ4_compressBound(source.size()));
290*795d594fSAndroid Build Coastguard Worker   size_t data_size = 0;
291*795d594fSAndroid Build Coastguard Worker   if (image_storage_mode == ImageHeader::kStorageModeLZ4) {
292*795d594fSAndroid Build Coastguard Worker     data_size = LZ4_compress_default(
293*795d594fSAndroid Build Coastguard Worker         reinterpret_cast<char*>(const_cast<uint8_t*>(source.data())),
294*795d594fSAndroid Build Coastguard Worker         reinterpret_cast<char*>(storage->data()),
295*795d594fSAndroid Build Coastguard Worker         source.size(),
296*795d594fSAndroid Build Coastguard Worker         storage->size());
297*795d594fSAndroid Build Coastguard Worker   } else {
298*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(image_storage_mode, ImageHeader::kStorageModeLZ4HC);
299*795d594fSAndroid Build Coastguard Worker     data_size = LZ4_compress_HC(
300*795d594fSAndroid Build Coastguard Worker         reinterpret_cast<const char*>(const_cast<uint8_t*>(source.data())),
301*795d594fSAndroid Build Coastguard Worker         reinterpret_cast<char*>(storage->data()),
302*795d594fSAndroid Build Coastguard Worker         source.size(),
303*795d594fSAndroid Build Coastguard Worker         storage->size(),
304*795d594fSAndroid Build Coastguard Worker         LZ4HC_CLEVEL_MAX);
305*795d594fSAndroid Build Coastguard Worker   }
306*795d594fSAndroid Build Coastguard Worker 
307*795d594fSAndroid Build Coastguard Worker   if (data_size == 0) {
308*795d594fSAndroid Build Coastguard Worker     return false;
309*795d594fSAndroid Build Coastguard Worker   }
310*795d594fSAndroid Build Coastguard Worker   storage->resize(data_size);
311*795d594fSAndroid Build Coastguard Worker 
312*795d594fSAndroid Build Coastguard Worker   VLOG(image) << "Compressed from " << source.size() << " to " << storage->size() << " in "
313*795d594fSAndroid Build Coastguard Worker               << PrettyDuration(NanoTime() - compress_start_time);
314*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
315*795d594fSAndroid Build Coastguard Worker     dchecked_vector<uint8_t> decompressed(source.size());
316*795d594fSAndroid Build Coastguard Worker     size_t decompressed_size;
317*795d594fSAndroid Build Coastguard Worker     std::string error_msg;
318*795d594fSAndroid Build Coastguard Worker     bool ok = LZ4_decompress_safe_checked(
319*795d594fSAndroid Build Coastguard Worker         reinterpret_cast<char*>(storage->data()),
320*795d594fSAndroid Build Coastguard Worker         reinterpret_cast<char*>(decompressed.data()),
321*795d594fSAndroid Build Coastguard Worker         storage->size(),
322*795d594fSAndroid Build Coastguard Worker         decompressed.size(),
323*795d594fSAndroid Build Coastguard Worker         &decompressed_size,
324*795d594fSAndroid Build Coastguard Worker         &error_msg);
325*795d594fSAndroid Build Coastguard Worker     if (!ok) {
326*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << error_msg;
327*795d594fSAndroid Build Coastguard Worker       UNREACHABLE();
328*795d594fSAndroid Build Coastguard Worker     }
329*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(decompressed_size, decompressed.size());
330*795d594fSAndroid Build Coastguard Worker     CHECK_EQ(memcmp(source.data(), decompressed.data(), source.size()), 0) << image_storage_mode;
331*795d594fSAndroid Build Coastguard Worker   }
332*795d594fSAndroid Build Coastguard Worker   return true;
333*795d594fSAndroid Build Coastguard Worker }
334*795d594fSAndroid Build Coastguard Worker 
WriteData(const ImageFileGuard & image_file,const uint8_t * data,const uint8_t * bitmap_data,ImageHeader::StorageMode image_storage_mode,uint32_t max_image_block_size,bool update_checksum,std::string * error_msg)335*795d594fSAndroid Build Coastguard Worker bool ImageHeader::WriteData(const ImageFileGuard& image_file,
336*795d594fSAndroid Build Coastguard Worker                             const uint8_t* data,
337*795d594fSAndroid Build Coastguard Worker                             const uint8_t* bitmap_data,
338*795d594fSAndroid Build Coastguard Worker                             ImageHeader::StorageMode image_storage_mode,
339*795d594fSAndroid Build Coastguard Worker                             uint32_t max_image_block_size,
340*795d594fSAndroid Build Coastguard Worker                             bool update_checksum,
341*795d594fSAndroid Build Coastguard Worker                             std::string* error_msg) {
342*795d594fSAndroid Build Coastguard Worker   const bool is_compressed = image_storage_mode != ImageHeader::kStorageModeUncompressed;
343*795d594fSAndroid Build Coastguard Worker   dchecked_vector<std::pair<uint32_t, uint32_t>> block_sources;
344*795d594fSAndroid Build Coastguard Worker   dchecked_vector<ImageHeader::Block> blocks;
345*795d594fSAndroid Build Coastguard Worker 
346*795d594fSAndroid Build Coastguard Worker   // Add a set of solid blocks such that no block is larger than the maximum size. A solid block
347*795d594fSAndroid Build Coastguard Worker   // is a block that must be decompressed all at once.
348*795d594fSAndroid Build Coastguard Worker   auto add_blocks = [&](uint32_t offset, uint32_t size) {
349*795d594fSAndroid Build Coastguard Worker     while (size != 0u) {
350*795d594fSAndroid Build Coastguard Worker       const uint32_t cur_size = std::min(size, max_image_block_size);
351*795d594fSAndroid Build Coastguard Worker       block_sources.emplace_back(offset, cur_size);
352*795d594fSAndroid Build Coastguard Worker       offset += cur_size;
353*795d594fSAndroid Build Coastguard Worker       size -= cur_size;
354*795d594fSAndroid Build Coastguard Worker     }
355*795d594fSAndroid Build Coastguard Worker   };
356*795d594fSAndroid Build Coastguard Worker 
357*795d594fSAndroid Build Coastguard Worker   add_blocks(sizeof(ImageHeader), this->GetImageSize() - sizeof(ImageHeader));
358*795d594fSAndroid Build Coastguard Worker 
359*795d594fSAndroid Build Coastguard Worker   // Checksum of compressed image data and header.
360*795d594fSAndroid Build Coastguard Worker   uint32_t image_checksum = 0u;
361*795d594fSAndroid Build Coastguard Worker   if (update_checksum) {
362*795d594fSAndroid Build Coastguard Worker     image_checksum = adler32(0L, Z_NULL, 0);
363*795d594fSAndroid Build Coastguard Worker     image_checksum = adler32(image_checksum,
364*795d594fSAndroid Build Coastguard Worker                              reinterpret_cast<const uint8_t*>(this),
365*795d594fSAndroid Build Coastguard Worker                              sizeof(ImageHeader));
366*795d594fSAndroid Build Coastguard Worker   }
367*795d594fSAndroid Build Coastguard Worker 
368*795d594fSAndroid Build Coastguard Worker   // Copy and compress blocks.
369*795d594fSAndroid Build Coastguard Worker   uint32_t out_offset = sizeof(ImageHeader);
370*795d594fSAndroid Build Coastguard Worker   for (const std::pair<uint32_t, uint32_t> block : block_sources) {
371*795d594fSAndroid Build Coastguard Worker     ArrayRef<const uint8_t> raw_image_data(data + block.first, block.second);
372*795d594fSAndroid Build Coastguard Worker     dchecked_vector<uint8_t> compressed_data;
373*795d594fSAndroid Build Coastguard Worker     ArrayRef<const uint8_t> image_data;
374*795d594fSAndroid Build Coastguard Worker     if (is_compressed) {
375*795d594fSAndroid Build Coastguard Worker       if (!CompressData(raw_image_data, image_storage_mode, &compressed_data)) {
376*795d594fSAndroid Build Coastguard Worker         *error_msg = "Error compressing data for " +
377*795d594fSAndroid Build Coastguard Worker             image_file->GetPath() + ": " + std::string(strerror(errno));
378*795d594fSAndroid Build Coastguard Worker         return false;
379*795d594fSAndroid Build Coastguard Worker       }
380*795d594fSAndroid Build Coastguard Worker       image_data = ArrayRef<const uint8_t>(compressed_data);
381*795d594fSAndroid Build Coastguard Worker     } else {
382*795d594fSAndroid Build Coastguard Worker       image_data = raw_image_data;
383*795d594fSAndroid Build Coastguard Worker       // For uncompressed, preserve alignment since the image will be directly mapped.
384*795d594fSAndroid Build Coastguard Worker       out_offset = block.first;
385*795d594fSAndroid Build Coastguard Worker     }
386*795d594fSAndroid Build Coastguard Worker 
387*795d594fSAndroid Build Coastguard Worker     // Fill in the compressed location of the block.
388*795d594fSAndroid Build Coastguard Worker     blocks.emplace_back(ImageHeader::Block(
389*795d594fSAndroid Build Coastguard Worker         image_storage_mode,
390*795d594fSAndroid Build Coastguard Worker         /*data_offset=*/ out_offset,
391*795d594fSAndroid Build Coastguard Worker         /*data_size=*/ image_data.size(),
392*795d594fSAndroid Build Coastguard Worker         /*image_offset=*/ block.first,
393*795d594fSAndroid Build Coastguard Worker         /*image_size=*/ block.second));
394*795d594fSAndroid Build Coastguard Worker 
395*795d594fSAndroid Build Coastguard Worker     if (!image_file->PwriteFully(image_data.data(), image_data.size(), out_offset)) {
396*795d594fSAndroid Build Coastguard Worker       *error_msg = "Failed to write image file data " +
397*795d594fSAndroid Build Coastguard Worker           image_file->GetPath() + ": " + std::string(strerror(errno));
398*795d594fSAndroid Build Coastguard Worker       return false;
399*795d594fSAndroid Build Coastguard Worker     }
400*795d594fSAndroid Build Coastguard Worker     out_offset += image_data.size();
401*795d594fSAndroid Build Coastguard Worker     if (update_checksum) {
402*795d594fSAndroid Build Coastguard Worker       image_checksum = adler32(image_checksum, image_data.data(), image_data.size());
403*795d594fSAndroid Build Coastguard Worker     }
404*795d594fSAndroid Build Coastguard Worker   }
405*795d594fSAndroid Build Coastguard Worker 
406*795d594fSAndroid Build Coastguard Worker   if (is_compressed) {
407*795d594fSAndroid Build Coastguard Worker     // Align up since the compressed data is not necessarily aligned.
408*795d594fSAndroid Build Coastguard Worker     out_offset = RoundUp(out_offset, alignof(ImageHeader::Block));
409*795d594fSAndroid Build Coastguard Worker     CHECK(!blocks.empty());
410*795d594fSAndroid Build Coastguard Worker     const size_t blocks_bytes = blocks.size() * sizeof(blocks[0]);
411*795d594fSAndroid Build Coastguard Worker     if (!image_file->PwriteFully(&blocks[0], blocks_bytes, out_offset)) {
412*795d594fSAndroid Build Coastguard Worker       *error_msg = "Failed to write image blocks " +
413*795d594fSAndroid Build Coastguard Worker           image_file->GetPath() + ": " + std::string(strerror(errno));
414*795d594fSAndroid Build Coastguard Worker       return false;
415*795d594fSAndroid Build Coastguard Worker     }
416*795d594fSAndroid Build Coastguard Worker     this->blocks_offset_ = out_offset;
417*795d594fSAndroid Build Coastguard Worker     this->blocks_count_ = blocks.size();
418*795d594fSAndroid Build Coastguard Worker     out_offset += blocks_bytes;
419*795d594fSAndroid Build Coastguard Worker   }
420*795d594fSAndroid Build Coastguard Worker 
421*795d594fSAndroid Build Coastguard Worker   // Data size includes everything except the bitmap.
422*795d594fSAndroid Build Coastguard Worker   this->data_size_ = out_offset - sizeof(ImageHeader);
423*795d594fSAndroid Build Coastguard Worker 
424*795d594fSAndroid Build Coastguard Worker   // Update and write the bitmap section. Note that the bitmap section is relative to the
425*795d594fSAndroid Build Coastguard Worker   // possibly compressed image.
426*795d594fSAndroid Build Coastguard Worker   ImageSection& bitmap_section = GetImageSection(ImageHeader::kSectionImageBitmap);
427*795d594fSAndroid Build Coastguard Worker   // Align up since data size may be unaligned if the image is compressed.
428*795d594fSAndroid Build Coastguard Worker   out_offset = RoundUp(out_offset, kElfSegmentAlignment);
429*795d594fSAndroid Build Coastguard Worker   bitmap_section = ImageSection(out_offset, bitmap_section.Size());
430*795d594fSAndroid Build Coastguard Worker 
431*795d594fSAndroid Build Coastguard Worker   if (!image_file->PwriteFully(bitmap_data,
432*795d594fSAndroid Build Coastguard Worker                                bitmap_section.Size(),
433*795d594fSAndroid Build Coastguard Worker                                bitmap_section.Offset())) {
434*795d594fSAndroid Build Coastguard Worker     *error_msg = "Failed to write image file bitmap " +
435*795d594fSAndroid Build Coastguard Worker         image_file->GetPath() + ": " + std::string(strerror(errno));
436*795d594fSAndroid Build Coastguard Worker     return false;
437*795d594fSAndroid Build Coastguard Worker   }
438*795d594fSAndroid Build Coastguard Worker 
439*795d594fSAndroid Build Coastguard Worker   int err = image_file->Flush();
440*795d594fSAndroid Build Coastguard Worker   if (err < 0) {
441*795d594fSAndroid Build Coastguard Worker     *error_msg = "Failed to flush image file " + image_file->GetPath() + ": " + std::to_string(err);
442*795d594fSAndroid Build Coastguard Worker     return false;
443*795d594fSAndroid Build Coastguard Worker   }
444*795d594fSAndroid Build Coastguard Worker 
445*795d594fSAndroid Build Coastguard Worker   if (update_checksum) {
446*795d594fSAndroid Build Coastguard Worker     // Calculate the image checksum of the remaining data.
447*795d594fSAndroid Build Coastguard Worker     image_checksum = adler32(image_checksum,
448*795d594fSAndroid Build Coastguard Worker                              reinterpret_cast<const uint8_t*>(bitmap_data),
449*795d594fSAndroid Build Coastguard Worker                              bitmap_section.Size());
450*795d594fSAndroid Build Coastguard Worker     this->SetImageChecksum(image_checksum);
451*795d594fSAndroid Build Coastguard Worker   }
452*795d594fSAndroid Build Coastguard Worker 
453*795d594fSAndroid Build Coastguard Worker   if (VLOG_IS_ON(image)) {
454*795d594fSAndroid Build Coastguard Worker     const size_t separately_written_section_size = bitmap_section.Size();
455*795d594fSAndroid Build Coastguard Worker     const size_t total_uncompressed_size = image_size_ + separately_written_section_size;
456*795d594fSAndroid Build Coastguard Worker     const size_t total_compressed_size = out_offset + separately_written_section_size;
457*795d594fSAndroid Build Coastguard Worker 
458*795d594fSAndroid Build Coastguard Worker     VLOG(compiler) << "UncompressedImageSize = " << total_uncompressed_size;
459*795d594fSAndroid Build Coastguard Worker     if (total_uncompressed_size != total_compressed_size) {
460*795d594fSAndroid Build Coastguard Worker       VLOG(compiler) << "CompressedImageSize = " << total_compressed_size;
461*795d594fSAndroid Build Coastguard Worker     }
462*795d594fSAndroid Build Coastguard Worker   }
463*795d594fSAndroid Build Coastguard Worker 
464*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(bitmap_section.End(), static_cast<size_t>(image_file->GetLength()))
465*795d594fSAndroid Build Coastguard Worker       << "Bitmap should be at the end of the file";
466*795d594fSAndroid Build Coastguard Worker   return true;
467*795d594fSAndroid Build Coastguard Worker }
468*795d594fSAndroid Build Coastguard Worker 
469*795d594fSAndroid Build Coastguard Worker }  // namespace art
470