• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "oat.h"
18 
19 #include <string.h>
20 
21 #include "android-base/stringprintf.h"
22 
23 #include "arch/instruction_set.h"
24 #include "arch/instruction_set_features.h"
25 #include "base/bit_utils.h"
26 #include "base/strlcpy.h"
27 
28 namespace art {
29 
30 using android::base::StringPrintf;
31 
32 constexpr const char OatHeader::kTrueValue[];
33 constexpr const char OatHeader::kFalseValue[];
34 
ComputeOatHeaderSize(const SafeMap<std::string,std::string> * variable_data)35 static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
36   size_t estimate = 0U;
37   if (variable_data != nullptr) {
38     SafeMap<std::string, std::string>::const_iterator it = variable_data->begin();
39     SafeMap<std::string, std::string>::const_iterator end = variable_data->end();
40     for ( ; it != end; ++it) {
41       estimate += it->first.length() + 1;
42       estimate += it->second.length() + 1;
43     }
44   }
45   return sizeof(OatHeader) + estimate;
46 }
47 
Create(InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,uint32_t dex_file_count,const SafeMap<std::string,std::string> * variable_data)48 OatHeader* OatHeader::Create(InstructionSet instruction_set,
49                              const InstructionSetFeatures* instruction_set_features,
50                              uint32_t dex_file_count,
51                              const SafeMap<std::string, std::string>* variable_data) {
52   // Estimate size of optional data.
53   size_t needed_size = ComputeOatHeaderSize(variable_data);
54 
55   // Reserve enough memory.
56   void* memory = operator new (needed_size);
57 
58   // Create the OatHeader in-place.
59   return new (memory) OatHeader(instruction_set,
60                                 instruction_set_features,
61                                 dex_file_count,
62                                 variable_data);
63 }
64 
OatHeader(InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,uint32_t dex_file_count,const SafeMap<std::string,std::string> * variable_data)65 OatHeader::OatHeader(InstructionSet instruction_set,
66                      const InstructionSetFeatures* instruction_set_features,
67                      uint32_t dex_file_count,
68                      const SafeMap<std::string, std::string>* variable_data)
69     : oat_checksum_(0u),
70       instruction_set_(instruction_set),
71       instruction_set_features_bitmap_(instruction_set_features->AsBitmap()),
72       dex_file_count_(dex_file_count),
73       oat_dex_files_offset_(0),
74       executable_offset_(0),
75       jni_dlsym_lookup_trampoline_offset_(0),
76       jni_dlsym_lookup_critical_trampoline_offset_(0),
77       quick_generic_jni_trampoline_offset_(0),
78       quick_imt_conflict_trampoline_offset_(0),
79       quick_resolution_trampoline_offset_(0),
80       quick_to_interpreter_bridge_offset_(0) {
81   // Don't want asserts in header as they would be checked in each file that includes it. But the
82   // fields are private, so we check inside a method.
83   static_assert(sizeof(magic_) == sizeof(kOatMagic),
84                 "Oat magic and magic_ have different lengths.");
85   static_assert(sizeof(version_) == sizeof(kOatVersion),
86                 "Oat version and version_ have different lengths.");
87 
88   magic_ = kOatMagic;
89   version_ = kOatVersion;
90 
91   CHECK_NE(instruction_set, InstructionSet::kNone);
92 
93   // Flatten the map. Will also update variable_size_data_size_.
94   Flatten(variable_data);
95 }
96 
IsValid() const97 bool OatHeader::IsValid() const {
98   if (magic_ != kOatMagic) {
99     return false;
100   }
101   if (version_ != kOatVersion) {
102     return false;
103   }
104   if (!IsAligned<kPageSize>(executable_offset_)) {
105     return false;
106   }
107   if (!IsValidInstructionSet(instruction_set_)) {
108     return false;
109   }
110   return true;
111 }
112 
GetValidationErrorMessage() const113 std::string OatHeader::GetValidationErrorMessage() const {
114   if (magic_ != kOatMagic) {
115     static_assert(sizeof(kOatMagic) == 4, "kOatMagic has unexpected length");
116     return StringPrintf("Invalid oat magic, expected 0x%02x%02x%02x%02x, got 0x%02x%02x%02x%02x.",
117                         kOatMagic[0], kOatMagic[1], kOatMagic[2], kOatMagic[3],
118                         magic_[0], magic_[1], magic_[2], magic_[3]);
119   }
120   if (version_ != kOatVersion) {
121     static_assert(sizeof(kOatVersion) == 4, "kOatVersion has unexpected length");
122     return StringPrintf("Invalid oat version, expected 0x%02x%02x%02x%02x, got 0x%02x%02x%02x%02x.",
123                         kOatVersion[0], kOatVersion[1], kOatVersion[2], kOatVersion[3],
124                         version_[0], version_[1], version_[2], version_[3]);
125   }
126   if (!IsAligned<kPageSize>(executable_offset_)) {
127     return "Executable offset not page-aligned.";
128   }
129   if (!IsValidInstructionSet(instruction_set_)) {
130     return StringPrintf("Invalid instruction set, %d.", static_cast<int>(instruction_set_));
131   }
132   return "";
133 }
134 
135 // Do not move this into the header.  The method must be compiled in the runtime library,
136 // so that we can check that the compile-time oat version matches the version in the caller.
CheckOatVersion(std::array<uint8_t,4> version)137 void OatHeader::CheckOatVersion(std::array<uint8_t, 4> version) {
138   constexpr std::array<uint8_t, 4> expected = kOatVersion;  // Runtime oat version.
139   if (version != kOatVersion) {
140     LOG(FATAL) << StringPrintf("Invalid oat version, expected 0x%02x%02x%02x%02x, "
141                                    "got 0x%02x%02x%02x%02x.",
142                                expected[0], expected[1], expected[2], expected[3],
143                                version[0], version[1], version[2], version[3]);
144   }
145 }
146 
GetMagic() const147 const char* OatHeader::GetMagic() const {
148   CHECK(IsValid());
149   return reinterpret_cast<const char*>(magic_.data());
150 }
151 
GetChecksum() const152 uint32_t OatHeader::GetChecksum() const {
153   CHECK(IsValid());
154   return oat_checksum_;
155 }
156 
SetChecksum(uint32_t oat_checksum)157 void OatHeader::SetChecksum(uint32_t oat_checksum) {
158   oat_checksum_ = oat_checksum;
159 }
160 
GetInstructionSet() const161 InstructionSet OatHeader::GetInstructionSet() const {
162   CHECK(IsValid());
163   return instruction_set_;
164 }
165 
GetInstructionSetFeaturesBitmap() const166 uint32_t OatHeader::GetInstructionSetFeaturesBitmap() const {
167   CHECK(IsValid());
168   return instruction_set_features_bitmap_;
169 }
170 
GetOatDexFilesOffset() const171 uint32_t OatHeader::GetOatDexFilesOffset() const {
172   DCHECK(IsValid());
173   DCHECK_GT(oat_dex_files_offset_, sizeof(OatHeader));
174   return oat_dex_files_offset_;
175 }
176 
SetOatDexFilesOffset(uint32_t oat_dex_files_offset)177 void OatHeader::SetOatDexFilesOffset(uint32_t oat_dex_files_offset) {
178   DCHECK_GT(oat_dex_files_offset, sizeof(OatHeader));
179   DCHECK(IsValid());
180   DCHECK_EQ(oat_dex_files_offset_, 0u);
181 
182   oat_dex_files_offset_ = oat_dex_files_offset;
183 }
184 
GetExecutableOffset() const185 uint32_t OatHeader::GetExecutableOffset() const {
186   DCHECK(IsValid());
187   DCHECK_ALIGNED(executable_offset_, kPageSize);
188   CHECK_GT(executable_offset_, sizeof(OatHeader));
189   return executable_offset_;
190 }
191 
SetExecutableOffset(uint32_t executable_offset)192 void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
193   DCHECK_ALIGNED(executable_offset, kPageSize);
194   CHECK_GT(executable_offset, sizeof(OatHeader));
195   DCHECK(IsValid());
196   DCHECK_EQ(executable_offset_, 0U);
197 
198   executable_offset_ = executable_offset;
199 }
200 
GetTrampoline(const OatHeader & header,uint32_t offset)201 static const void* GetTrampoline(const OatHeader& header, uint32_t offset) {
202   return (offset != 0u) ? reinterpret_cast<const uint8_t*>(&header) + offset : nullptr;
203 }
204 
GetJniDlsymLookupTrampoline() const205 const void* OatHeader::GetJniDlsymLookupTrampoline() const {
206   return GetTrampoline(*this, GetJniDlsymLookupTrampolineOffset());
207 }
208 
GetJniDlsymLookupTrampolineOffset() const209 uint32_t OatHeader::GetJniDlsymLookupTrampolineOffset() const {
210   DCHECK(IsValid());
211   return jni_dlsym_lookup_trampoline_offset_;
212 }
213 
SetJniDlsymLookupTrampolineOffset(uint32_t offset)214 void OatHeader::SetJniDlsymLookupTrampolineOffset(uint32_t offset) {
215   DCHECK(IsValid());
216   DCHECK_EQ(jni_dlsym_lookup_trampoline_offset_, 0U) << offset;
217 
218   jni_dlsym_lookup_trampoline_offset_ = offset;
219 }
220 
GetJniDlsymLookupCriticalTrampoline() const221 const void* OatHeader::GetJniDlsymLookupCriticalTrampoline() const {
222   return GetTrampoline(*this, GetJniDlsymLookupCriticalTrampolineOffset());
223 }
224 
GetJniDlsymLookupCriticalTrampolineOffset() const225 uint32_t OatHeader::GetJniDlsymLookupCriticalTrampolineOffset() const {
226   DCHECK(IsValid());
227   return jni_dlsym_lookup_critical_trampoline_offset_;
228 }
229 
SetJniDlsymLookupCriticalTrampolineOffset(uint32_t offset)230 void OatHeader::SetJniDlsymLookupCriticalTrampolineOffset(uint32_t offset) {
231   DCHECK(IsValid());
232   DCHECK_EQ(jni_dlsym_lookup_critical_trampoline_offset_, 0U) << offset;
233 
234   jni_dlsym_lookup_critical_trampoline_offset_ = offset;
235 }
236 
GetQuickGenericJniTrampoline() const237 const void* OatHeader::GetQuickGenericJniTrampoline() const {
238   return GetTrampoline(*this, GetQuickGenericJniTrampolineOffset());
239 }
240 
GetQuickGenericJniTrampolineOffset() const241 uint32_t OatHeader::GetQuickGenericJniTrampolineOffset() const {
242   DCHECK(IsValid());
243   CHECK_GE(quick_generic_jni_trampoline_offset_, jni_dlsym_lookup_trampoline_offset_);
244   return quick_generic_jni_trampoline_offset_;
245 }
246 
SetQuickGenericJniTrampolineOffset(uint32_t offset)247 void OatHeader::SetQuickGenericJniTrampolineOffset(uint32_t offset) {
248   CHECK(offset == 0 || offset >= jni_dlsym_lookup_trampoline_offset_);
249   DCHECK(IsValid());
250   DCHECK_EQ(quick_generic_jni_trampoline_offset_, 0U) << offset;
251 
252   quick_generic_jni_trampoline_offset_ = offset;
253 }
254 
GetQuickImtConflictTrampoline() const255 const void* OatHeader::GetQuickImtConflictTrampoline() const {
256   return GetTrampoline(*this, GetQuickImtConflictTrampolineOffset());
257 }
258 
GetQuickImtConflictTrampolineOffset() const259 uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const {
260   DCHECK(IsValid());
261   CHECK_GE(quick_imt_conflict_trampoline_offset_, quick_generic_jni_trampoline_offset_);
262   return quick_imt_conflict_trampoline_offset_;
263 }
264 
SetQuickImtConflictTrampolineOffset(uint32_t offset)265 void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) {
266   CHECK(offset == 0 || offset >= quick_generic_jni_trampoline_offset_);
267   DCHECK(IsValid());
268   DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset;
269 
270   quick_imt_conflict_trampoline_offset_ = offset;
271 }
272 
GetQuickResolutionTrampoline() const273 const void* OatHeader::GetQuickResolutionTrampoline() const {
274   return GetTrampoline(*this, GetQuickResolutionTrampolineOffset());
275 }
276 
GetQuickResolutionTrampolineOffset() const277 uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
278   DCHECK(IsValid());
279   CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_);
280   return quick_resolution_trampoline_offset_;
281 }
282 
SetQuickResolutionTrampolineOffset(uint32_t offset)283 void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
284   CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_);
285   DCHECK(IsValid());
286   DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;
287 
288   quick_resolution_trampoline_offset_ = offset;
289 }
290 
GetQuickToInterpreterBridge() const291 const void* OatHeader::GetQuickToInterpreterBridge() const {
292   return GetTrampoline(*this, GetQuickToInterpreterBridgeOffset());
293 }
294 
GetQuickToInterpreterBridgeOffset() const295 uint32_t OatHeader::GetQuickToInterpreterBridgeOffset() const {
296   DCHECK(IsValid());
297   CHECK_GE(quick_to_interpreter_bridge_offset_, quick_resolution_trampoline_offset_);
298   return quick_to_interpreter_bridge_offset_;
299 }
300 
SetQuickToInterpreterBridgeOffset(uint32_t offset)301 void OatHeader::SetQuickToInterpreterBridgeOffset(uint32_t offset) {
302   CHECK(offset == 0 || offset >= quick_resolution_trampoline_offset_);
303   DCHECK(IsValid());
304   DCHECK_EQ(quick_to_interpreter_bridge_offset_, 0U) << offset;
305 
306   quick_to_interpreter_bridge_offset_ = offset;
307 }
308 
GetKeyValueStoreSize() const309 uint32_t OatHeader::GetKeyValueStoreSize() const {
310   CHECK(IsValid());
311   return key_value_store_size_;
312 }
313 
GetKeyValueStore() const314 const uint8_t* OatHeader::GetKeyValueStore() const {
315   CHECK(IsValid());
316   return key_value_store_;
317 }
318 
319 // Advance start until it is either end or \0.
ParseString(const char * start,const char * end)320 static const char* ParseString(const char* start, const char* end) {
321   while (start < end && *start != 0) {
322     start++;
323   }
324   return start;
325 }
326 
GetStoreValueByKey(const char * key) const327 const char* OatHeader::GetStoreValueByKey(const char* key) const {
328   const char* ptr = reinterpret_cast<const char*>(&key_value_store_);
329   const char* end = ptr + key_value_store_size_;
330 
331   while (ptr < end) {
332     // Scan for a closing zero.
333     const char* str_end = ParseString(ptr, end);
334     if (str_end < end) {
335       if (strcmp(key, ptr) == 0) {
336         // Same as key. Check if value is OK.
337         if (ParseString(str_end + 1, end) < end) {
338           return str_end + 1;
339         }
340       } else {
341         // Different from key. Advance over the value.
342         ptr = ParseString(str_end + 1, end) + 1;
343       }
344     } else {
345       break;
346     }
347   }
348   // Not found.
349   return nullptr;
350 }
351 
GetStoreKeyValuePairByIndex(size_t index,const char ** key,const char ** value) const352 bool OatHeader::GetStoreKeyValuePairByIndex(size_t index, const char** key,
353                                             const char** value) const {
354   const char* ptr = reinterpret_cast<const char*>(&key_value_store_);
355   const char* end = ptr + key_value_store_size_;
356   ssize_t counter = static_cast<ssize_t>(index);
357 
358   while (ptr < end && counter >= 0) {
359     // Scan for a closing zero.
360     const char* str_end = ParseString(ptr, end);
361     if (str_end < end) {
362       const char* maybe_key = ptr;
363       ptr = ParseString(str_end + 1, end) + 1;
364       if (ptr <= end) {
365         if (counter == 0) {
366           *key = maybe_key;
367           *value = str_end + 1;
368           return true;
369         } else {
370           counter--;
371         }
372       } else {
373         return false;
374       }
375     } else {
376       break;
377     }
378   }
379   // Not found.
380   return false;
381 }
382 
GetHeaderSize() const383 size_t OatHeader::GetHeaderSize() const {
384   return sizeof(OatHeader) + key_value_store_size_;
385 }
386 
IsDebuggable() const387 bool OatHeader::IsDebuggable() const {
388   return IsKeyEnabled(OatHeader::kDebuggableKey);
389 }
390 
IsConcurrentCopying() const391 bool OatHeader::IsConcurrentCopying() const {
392   return IsKeyEnabled(OatHeader::kConcurrentCopying);
393 }
394 
IsNativeDebuggable() const395 bool OatHeader::IsNativeDebuggable() const {
396   return IsKeyEnabled(OatHeader::kNativeDebuggableKey);
397 }
398 
GetCompilerFilter() const399 CompilerFilter::Filter OatHeader::GetCompilerFilter() const {
400   CompilerFilter::Filter filter;
401   const char* key_value = GetStoreValueByKey(kCompilerFilter);
402   CHECK(key_value != nullptr) << "compiler-filter not found in oat header";
403   CHECK(CompilerFilter::ParseCompilerFilter(key_value, &filter))
404       << "Invalid compiler-filter in oat header: " << key_value;
405   return filter;
406 }
407 
KeyHasValue(const char * key,const char * value,size_t value_size) const408 bool OatHeader::KeyHasValue(const char* key, const char* value, size_t value_size) const {
409   const char* key_value = GetStoreValueByKey(key);
410   return (key_value != nullptr && strncmp(key_value, value, value_size) == 0);
411 }
412 
IsKeyEnabled(const char * key) const413 bool OatHeader::IsKeyEnabled(const char* key) const {
414   return KeyHasValue(key, kTrueValue, sizeof(kTrueValue));
415 }
416 
Flatten(const SafeMap<std::string,std::string> * key_value_store)417 void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store) {
418   char* data_ptr = reinterpret_cast<char*>(&key_value_store_);
419   if (key_value_store != nullptr) {
420     SafeMap<std::string, std::string>::const_iterator it = key_value_store->begin();
421     SafeMap<std::string, std::string>::const_iterator end = key_value_store->end();
422     for ( ; it != end; ++it) {
423       strlcpy(data_ptr, it->first.c_str(), it->first.length() + 1);
424       data_ptr += it->first.length() + 1;
425       strlcpy(data_ptr, it->second.c_str(), it->second.length() + 1);
426       data_ptr += it->second.length() + 1;
427     }
428   }
429   key_value_store_size_ = data_ptr - reinterpret_cast<char*>(&key_value_store_);
430 }
431 
432 }  // namespace art
433