1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "image.h"
18
19#include "base/bit_utils.h"
20#include "base/length_prefixed_array.h"
21#include "mirror/object_array.h"
22#include "mirror/object_array-inl.h"
23#include "mirror/object-inl.h"
24#include "utils.h"
25
26namespace art {
27
28const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
29const uint8_t ImageHeader::kImageVersion[] = { '0', '4', '3', '\0' };  // hash-based DexCache fields
30
31ImageHeader::ImageHeader(uint32_t image_begin,
32                         uint32_t image_size,
33                         ImageSection* sections,
34                         uint32_t image_roots,
35                         uint32_t oat_checksum,
36                         uint32_t oat_file_begin,
37                         uint32_t oat_data_begin,
38                         uint32_t oat_data_end,
39                         uint32_t oat_file_end,
40                         uint32_t boot_image_begin,
41                         uint32_t boot_image_size,
42                         uint32_t boot_oat_begin,
43                         uint32_t boot_oat_size,
44                         uint32_t pointer_size,
45                         bool compile_pic,
46                         bool is_pic,
47                         StorageMode storage_mode,
48                         size_t data_size)
49  : image_begin_(image_begin),
50    image_size_(image_size),
51    oat_checksum_(oat_checksum),
52    oat_file_begin_(oat_file_begin),
53    oat_data_begin_(oat_data_begin),
54    oat_data_end_(oat_data_end),
55    oat_file_end_(oat_file_end),
56    boot_image_begin_(boot_image_begin),
57    boot_image_size_(boot_image_size),
58    boot_oat_begin_(boot_oat_begin),
59    boot_oat_size_(boot_oat_size),
60    patch_delta_(0),
61    image_roots_(image_roots),
62    pointer_size_(pointer_size),
63    compile_pic_(compile_pic),
64    is_pic_(is_pic),
65    storage_mode_(storage_mode),
66    data_size_(data_size) {
67  CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize));
68  CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kPageSize));
69  CHECK_EQ(oat_data_begin, RoundUp(oat_data_begin, kPageSize));
70  CHECK_LT(image_roots, oat_file_begin);
71  CHECK_LE(oat_file_begin, oat_data_begin);
72  CHECK_LT(oat_data_begin, oat_data_end);
73  CHECK_LE(oat_data_end, oat_file_end);
74  CHECK(ValidPointerSize(pointer_size_)) << pointer_size_;
75  memcpy(magic_, kImageMagic, sizeof(kImageMagic));
76  memcpy(version_, kImageVersion, sizeof(kImageVersion));
77  std::copy_n(sections, kSectionCount, sections_);
78}
79
80void ImageHeader::RelocateImage(off_t delta) {
81  CHECK_ALIGNED(delta, kPageSize) << " patch delta must be page aligned";
82  oat_file_begin_ += delta;
83  oat_data_begin_ += delta;
84  oat_data_end_ += delta;
85  oat_file_end_ += delta;
86  patch_delta_ += delta;
87  RelocateImageObjects(delta);
88  RelocateImageMethods(delta);
89}
90
91void ImageHeader::RelocateImageObjects(off_t delta) {
92  image_begin_ += delta;
93  image_roots_ += delta;
94}
95
96void ImageHeader::RelocateImageMethods(off_t delta) {
97  for (size_t i = 0; i < kImageMethodsCount; ++i) {
98    image_methods_[i] += delta;
99  }
100}
101
102bool ImageHeader::IsValid() const {
103  if (memcmp(magic_, kImageMagic, sizeof(kImageMagic)) != 0) {
104    return false;
105  }
106  if (memcmp(version_, kImageVersion, sizeof(kImageVersion)) != 0) {
107    return false;
108  }
109  // Unsigned so wraparound is well defined.
110  if (image_begin_ >= image_begin_ + image_size_) {
111    return false;
112  }
113  if (oat_file_begin_ > oat_file_end_) {
114    return false;
115  }
116  if (oat_data_begin_ > oat_data_end_) {
117    return false;
118  }
119  if (oat_file_begin_ >= oat_data_begin_) {
120    return false;
121  }
122  if (!IsAligned<kPageSize>(patch_delta_)) {
123    return false;
124  }
125  return true;
126}
127
128const char* ImageHeader::GetMagic() const {
129  CHECK(IsValid());
130  return reinterpret_cast<const char*>(magic_);
131}
132
133ArtMethod* ImageHeader::GetImageMethod(ImageMethod index) const {
134  CHECK_LT(static_cast<size_t>(index), kImageMethodsCount);
135  return reinterpret_cast<ArtMethod*>(image_methods_[index]);
136}
137
138void ImageHeader::SetImageMethod(ImageMethod index, ArtMethod* method) {
139  CHECK_LT(static_cast<size_t>(index), kImageMethodsCount);
140  image_methods_[index] = reinterpret_cast<uint64_t>(method);
141}
142
143const ImageSection& ImageHeader::GetImageSection(ImageSections index) const {
144  CHECK_LT(static_cast<size_t>(index), kSectionCount);
145  return sections_[index];
146}
147
148std::ostream& operator<<(std::ostream& os, const ImageSection& section) {
149  return os << "size=" << section.Size() << " range=" << section.Offset() << "-" << section.End();
150}
151
152void ImageHeader::VisitPackedArtFields(ArtFieldVisitor* visitor, uint8_t* base) const {
153  const ImageSection& fields = GetFieldsSection();
154  for (size_t pos = 0; pos < fields.Size(); ) {
155    auto* array = reinterpret_cast<LengthPrefixedArray<ArtField>*>(base + fields.Offset() + pos);
156    for (size_t i = 0; i < array->size(); ++i) {
157      visitor->Visit(&array->At(i, sizeof(ArtField)));
158    }
159    pos += array->ComputeSize(array->size());
160  }
161}
162
163void ImageHeader::VisitPackedArtMethods(ArtMethodVisitor* visitor,
164                                        uint8_t* base,
165                                        PointerSize pointer_size) const {
166  const size_t method_alignment = ArtMethod::Alignment(pointer_size);
167  const size_t method_size = ArtMethod::Size(pointer_size);
168  const ImageSection& methods = GetMethodsSection();
169  for (size_t pos = 0; pos < methods.Size(); ) {
170    auto* array = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(base + methods.Offset() + pos);
171    for (size_t i = 0; i < array->size(); ++i) {
172      visitor->Visit(&array->At(i, method_size, method_alignment));
173    }
174    pos += array->ComputeSize(array->size(), method_size, method_alignment);
175  }
176  const ImageSection& runtime_methods = GetRuntimeMethodsSection();
177  for (size_t pos = 0; pos < runtime_methods.Size(); ) {
178    auto* method = reinterpret_cast<ArtMethod*>(base + runtime_methods.Offset() + pos);
179    visitor->Visit(method);
180    pos += method_size;
181  }
182}
183
184PointerSize ImageHeader::GetPointerSize() const {
185  return ConvertToPointerSize(pointer_size_);
186}
187
188}  // namespace art
189