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
ComputeOatHeaderSize(const SafeMap<std::string,std::string> * variable_data)32 static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
33 size_t estimate = 0U;
34 if (variable_data != nullptr) {
35 SafeMap<std::string, std::string>::const_iterator it = variable_data->begin();
36 SafeMap<std::string, std::string>::const_iterator end = variable_data->end();
37 for ( ; it != end; ++it) {
38 estimate += it->first.length() + 1;
39 estimate += it->second.length() + 1;
40 }
41 }
42 return sizeof(OatHeader) + estimate;
43 }
44
Create(InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,uint32_t dex_file_count,const SafeMap<std::string,std::string> * variable_data)45 OatHeader* OatHeader::Create(InstructionSet instruction_set,
46 const InstructionSetFeatures* instruction_set_features,
47 uint32_t dex_file_count,
48 const SafeMap<std::string, std::string>* variable_data) {
49 // Estimate size of optional data.
50 size_t needed_size = ComputeOatHeaderSize(variable_data);
51
52 // Reserve enough memory.
53 void* memory = operator new (needed_size);
54
55 // Create the OatHeader in-place.
56 return new (memory) OatHeader(instruction_set,
57 instruction_set_features,
58 dex_file_count,
59 variable_data);
60 }
61
OatHeader(InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,uint32_t dex_file_count,const SafeMap<std::string,std::string> * variable_data)62 OatHeader::OatHeader(InstructionSet instruction_set,
63 const InstructionSetFeatures* instruction_set_features,
64 uint32_t dex_file_count,
65 const SafeMap<std::string, std::string>* variable_data)
66 : oat_checksum_(0u),
67 instruction_set_(instruction_set),
68 instruction_set_features_bitmap_(instruction_set_features->AsBitmap()),
69 dex_file_count_(dex_file_count),
70 oat_dex_files_offset_(0),
71 bcp_bss_info_offset_(0),
72 executable_offset_(0),
73 jni_dlsym_lookup_trampoline_offset_(0),
74 jni_dlsym_lookup_critical_trampoline_offset_(0),
75 quick_generic_jni_trampoline_offset_(0),
76 quick_imt_conflict_trampoline_offset_(0),
77 quick_resolution_trampoline_offset_(0),
78 quick_to_interpreter_bridge_offset_(0),
79 nterp_trampoline_offset_(0) {
80 // Don't want asserts in header as they would be checked in each file that includes it. But the
81 // fields are private, so we check inside a method.
82 static_assert(decltype(magic_)().size() == kOatMagic.size(),
83 "Oat magic and magic_ have different lengths.");
84 static_assert(decltype(version_)().size() == kOatVersion.size(),
85 "Oat version and version_ have different lengths.");
86
87 magic_ = kOatMagic;
88 version_ = kOatVersion;
89
90 CHECK_NE(instruction_set, InstructionSet::kNone);
91
92 // Flatten the map. Will also update variable_size_data_size_.
93 Flatten(variable_data);
94 }
95
IsValid() const96 bool OatHeader::IsValid() const {
97 if (magic_ != kOatMagic) {
98 return false;
99 }
100 if (version_ != kOatVersion) {
101 return false;
102 }
103 if (!IsAligned<kPageSize>(executable_offset_)) {
104 return false;
105 }
106 if (!IsValidInstructionSet(instruction_set_)) {
107 return false;
108 }
109 return true;
110 }
111
GetValidationErrorMessage() const112 std::string OatHeader::GetValidationErrorMessage() const {
113 if (magic_ != kOatMagic) {
114 static_assert(kOatMagic.size() == 4, "kOatMagic has unexpected length");
115 return StringPrintf("Invalid oat magic, expected 0x%02x%02x%02x%02x, got 0x%02x%02x%02x%02x.",
116 kOatMagic[0], kOatMagic[1], kOatMagic[2], kOatMagic[3],
117 magic_[0], magic_[1], magic_[2], magic_[3]);
118 }
119 if (version_ != kOatVersion) {
120 static_assert(kOatVersion.size() == 4, "kOatVersion has unexpected length");
121 return StringPrintf("Invalid oat version, expected 0x%02x%02x%02x%02x, got 0x%02x%02x%02x%02x.",
122 kOatVersion[0], kOatVersion[1], kOatVersion[2], kOatVersion[3],
123 version_[0], version_[1], version_[2], version_[3]);
124 }
125 if (!IsAligned<kPageSize>(executable_offset_)) {
126 return "Executable offset not page-aligned.";
127 }
128 if (!IsValidInstructionSet(instruction_set_)) {
129 return StringPrintf("Invalid instruction set, %d.", static_cast<int>(instruction_set_));
130 }
131 return "";
132 }
133
134 // Do not move this into the header. The method must be compiled in the runtime library,
135 // so that we can check that the compile-time oat version matches the version in the caller.
CheckOatVersion(std::array<uint8_t,4> version)136 void OatHeader::CheckOatVersion(std::array<uint8_t, 4> version) {
137 constexpr std::array<uint8_t, 4> expected = kOatVersion; // Runtime oat version.
138 if (version != kOatVersion) {
139 LOG(FATAL) << StringPrintf("Invalid oat version, expected 0x%02x%02x%02x%02x, "
140 "got 0x%02x%02x%02x%02x.",
141 expected[0], expected[1], expected[2], expected[3],
142 version[0], version[1], version[2], version[3]);
143 }
144 }
145
GetMagic() const146 const char* OatHeader::GetMagic() const {
147 CHECK(IsValid());
148 return reinterpret_cast<const char*>(magic_.data());
149 }
150
GetChecksum() const151 uint32_t OatHeader::GetChecksum() const {
152 CHECK(IsValid());
153 return oat_checksum_;
154 }
155
SetChecksum(uint32_t oat_checksum)156 void OatHeader::SetChecksum(uint32_t oat_checksum) {
157 oat_checksum_ = oat_checksum;
158 }
159
GetInstructionSet() const160 InstructionSet OatHeader::GetInstructionSet() const {
161 CHECK(IsValid());
162 return instruction_set_;
163 }
164
GetInstructionSetFeaturesBitmap() const165 uint32_t OatHeader::GetInstructionSetFeaturesBitmap() const {
166 CHECK(IsValid());
167 return instruction_set_features_bitmap_;
168 }
169
GetOatDexFilesOffset() const170 uint32_t OatHeader::GetOatDexFilesOffset() const {
171 DCHECK(IsValid());
172 DCHECK_GT(oat_dex_files_offset_, sizeof(OatHeader));
173 return oat_dex_files_offset_;
174 }
175
SetOatDexFilesOffset(uint32_t oat_dex_files_offset)176 void OatHeader::SetOatDexFilesOffset(uint32_t oat_dex_files_offset) {
177 DCHECK_GT(oat_dex_files_offset, sizeof(OatHeader));
178 DCHECK(IsValid());
179 DCHECK_EQ(oat_dex_files_offset_, 0u);
180
181 oat_dex_files_offset_ = oat_dex_files_offset;
182 }
183
GetBcpBssInfoOffset() const184 uint32_t OatHeader::GetBcpBssInfoOffset() const {
185 DCHECK(IsValid());
186 DCHECK(bcp_bss_info_offset_ == 0u || bcp_bss_info_offset_ > sizeof(OatHeader))
187 << "bcp_bss_info_offset_: " << bcp_bss_info_offset_
188 << "sizeof(OatHeader): " << sizeof(OatHeader);
189 return bcp_bss_info_offset_;
190 }
191
SetBcpBssInfoOffset(uint32_t bcp_info_offset)192 void OatHeader::SetBcpBssInfoOffset(uint32_t bcp_info_offset) {
193 DCHECK_GT(bcp_info_offset, sizeof(OatHeader));
194 DCHECK(IsValid());
195 DCHECK_EQ(bcp_bss_info_offset_, 0u);
196
197 bcp_bss_info_offset_ = bcp_info_offset;
198 }
199
GetExecutableOffset() const200 uint32_t OatHeader::GetExecutableOffset() const {
201 DCHECK(IsValid());
202 DCHECK_ALIGNED(executable_offset_, kPageSize);
203 CHECK_GT(executable_offset_, sizeof(OatHeader));
204 return executable_offset_;
205 }
206
SetExecutableOffset(uint32_t executable_offset)207 void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
208 DCHECK_ALIGNED(executable_offset, kPageSize);
209 CHECK_GT(executable_offset, sizeof(OatHeader));
210 DCHECK(IsValid());
211 DCHECK_EQ(executable_offset_, 0U);
212
213 executable_offset_ = executable_offset;
214 }
215
GetTrampoline(const OatHeader & header,uint32_t offset)216 static const void* GetTrampoline(const OatHeader& header, uint32_t offset) {
217 return (offset != 0u) ? reinterpret_cast<const uint8_t*>(&header) + offset : nullptr;
218 }
219
GetJniDlsymLookupTrampoline() const220 const void* OatHeader::GetJniDlsymLookupTrampoline() const {
221 return GetTrampoline(*this, GetJniDlsymLookupTrampolineOffset());
222 }
223
GetJniDlsymLookupTrampolineOffset() const224 uint32_t OatHeader::GetJniDlsymLookupTrampolineOffset() const {
225 DCHECK(IsValid());
226 return jni_dlsym_lookup_trampoline_offset_;
227 }
228
SetJniDlsymLookupTrampolineOffset(uint32_t offset)229 void OatHeader::SetJniDlsymLookupTrampolineOffset(uint32_t offset) {
230 DCHECK(IsValid());
231 DCHECK_EQ(jni_dlsym_lookup_trampoline_offset_, 0U) << offset;
232
233 jni_dlsym_lookup_trampoline_offset_ = offset;
234 }
235
GetJniDlsymLookupCriticalTrampoline() const236 const void* OatHeader::GetJniDlsymLookupCriticalTrampoline() const {
237 return GetTrampoline(*this, GetJniDlsymLookupCriticalTrampolineOffset());
238 }
239
GetJniDlsymLookupCriticalTrampolineOffset() const240 uint32_t OatHeader::GetJniDlsymLookupCriticalTrampolineOffset() const {
241 DCHECK(IsValid());
242 return jni_dlsym_lookup_critical_trampoline_offset_;
243 }
244
SetJniDlsymLookupCriticalTrampolineOffset(uint32_t offset)245 void OatHeader::SetJniDlsymLookupCriticalTrampolineOffset(uint32_t offset) {
246 DCHECK(IsValid());
247 DCHECK_EQ(jni_dlsym_lookup_critical_trampoline_offset_, 0U) << offset;
248
249 jni_dlsym_lookup_critical_trampoline_offset_ = offset;
250 }
251
GetQuickGenericJniTrampoline() const252 const void* OatHeader::GetQuickGenericJniTrampoline() const {
253 return GetTrampoline(*this, GetQuickGenericJniTrampolineOffset());
254 }
255
GetQuickGenericJniTrampolineOffset() const256 uint32_t OatHeader::GetQuickGenericJniTrampolineOffset() const {
257 DCHECK(IsValid());
258 CHECK_GE(quick_generic_jni_trampoline_offset_, jni_dlsym_lookup_trampoline_offset_);
259 return quick_generic_jni_trampoline_offset_;
260 }
261
SetQuickGenericJniTrampolineOffset(uint32_t offset)262 void OatHeader::SetQuickGenericJniTrampolineOffset(uint32_t offset) {
263 CHECK(offset == 0 || offset >= jni_dlsym_lookup_trampoline_offset_);
264 DCHECK(IsValid());
265 DCHECK_EQ(quick_generic_jni_trampoline_offset_, 0U) << offset;
266
267 quick_generic_jni_trampoline_offset_ = offset;
268 }
269
GetQuickImtConflictTrampoline() const270 const void* OatHeader::GetQuickImtConflictTrampoline() const {
271 return GetTrampoline(*this, GetQuickImtConflictTrampolineOffset());
272 }
273
GetQuickImtConflictTrampolineOffset() const274 uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const {
275 DCHECK(IsValid());
276 CHECK_GE(quick_imt_conflict_trampoline_offset_, quick_generic_jni_trampoline_offset_);
277 return quick_imt_conflict_trampoline_offset_;
278 }
279
SetQuickImtConflictTrampolineOffset(uint32_t offset)280 void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) {
281 CHECK(offset == 0 || offset >= quick_generic_jni_trampoline_offset_);
282 DCHECK(IsValid());
283 DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset;
284
285 quick_imt_conflict_trampoline_offset_ = offset;
286 }
287
GetQuickResolutionTrampoline() const288 const void* OatHeader::GetQuickResolutionTrampoline() const {
289 return GetTrampoline(*this, GetQuickResolutionTrampolineOffset());
290 }
291
GetQuickResolutionTrampolineOffset() const292 uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
293 DCHECK(IsValid());
294 CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_);
295 return quick_resolution_trampoline_offset_;
296 }
297
SetQuickResolutionTrampolineOffset(uint32_t offset)298 void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
299 CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_);
300 DCHECK(IsValid());
301 DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;
302
303 quick_resolution_trampoline_offset_ = offset;
304 }
305
GetQuickToInterpreterBridge() const306 const void* OatHeader::GetQuickToInterpreterBridge() const {
307 return GetTrampoline(*this, GetQuickToInterpreterBridgeOffset());
308 }
309
GetQuickToInterpreterBridgeOffset() const310 uint32_t OatHeader::GetQuickToInterpreterBridgeOffset() const {
311 DCHECK(IsValid());
312 CHECK_GE(quick_to_interpreter_bridge_offset_, quick_resolution_trampoline_offset_);
313 return quick_to_interpreter_bridge_offset_;
314 }
315
SetQuickToInterpreterBridgeOffset(uint32_t offset)316 void OatHeader::SetQuickToInterpreterBridgeOffset(uint32_t offset) {
317 CHECK(offset == 0 || offset >= quick_resolution_trampoline_offset_);
318 DCHECK(IsValid());
319 DCHECK_EQ(quick_to_interpreter_bridge_offset_, 0U) << offset;
320
321 quick_to_interpreter_bridge_offset_ = offset;
322 }
323
GetNterpTrampoline() const324 const void* OatHeader::GetNterpTrampoline() const {
325 return GetTrampoline(*this, GetNterpTrampolineOffset());
326 }
327
GetNterpTrampolineOffset() const328 uint32_t OatHeader::GetNterpTrampolineOffset() const {
329 DCHECK(IsValid());
330 CHECK_GE(nterp_trampoline_offset_, quick_to_interpreter_bridge_offset_);
331 return nterp_trampoline_offset_;
332 }
333
SetNterpTrampolineOffset(uint32_t offset)334 void OatHeader::SetNterpTrampolineOffset(uint32_t offset) {
335 CHECK(offset == 0 || offset >= quick_to_interpreter_bridge_offset_);
336 DCHECK(IsValid());
337 DCHECK_EQ(nterp_trampoline_offset_, 0U) << offset;
338
339 nterp_trampoline_offset_ = offset;
340 }
341
GetKeyValueStoreSize() const342 uint32_t OatHeader::GetKeyValueStoreSize() const {
343 CHECK(IsValid());
344 return key_value_store_size_;
345 }
346
GetKeyValueStore() const347 const uint8_t* OatHeader::GetKeyValueStore() const {
348 CHECK(IsValid());
349 return key_value_store_;
350 }
351
GetStoreValueByKey(const char * key) const352 const char* OatHeader::GetStoreValueByKey(const char* key) const {
353 std::string_view key_view(key);
354 const char* ptr = reinterpret_cast<const char*>(&key_value_store_);
355 const char* end = ptr + key_value_store_size_;
356
357 while (ptr < end) {
358 // Scan for a closing zero.
359 const char* str_end = reinterpret_cast<const char*>(memchr(ptr, 0, end - ptr));
360 if (UNLIKELY(str_end == nullptr)) {
361 LOG(WARNING) << "OatHeader: Unterminated key in key value store.";
362 return nullptr;
363 }
364 const char* value_start = str_end + 1;
365 const char* value_end =
366 reinterpret_cast<const char*>(memchr(value_start, 0, end - value_start));
367 if (UNLIKELY(value_end == nullptr)) {
368 LOG(WARNING) << "OatHeader: Unterminated value in key value store.";
369 return nullptr;
370 }
371 if (key_view == std::string_view(ptr, str_end - ptr)) {
372 // Same as key.
373 return value_start;
374 }
375 // Different from key. Advance over the value.
376 ptr = value_end + 1;
377 }
378 // Not found.
379 return nullptr;
380 }
381
GetStoreKeyValuePairByIndex(size_t index,const char ** key,const char ** value) const382 bool OatHeader::GetStoreKeyValuePairByIndex(size_t index,
383 const char** key,
384 const char** value) const {
385 const char* ptr = reinterpret_cast<const char*>(&key_value_store_);
386 const char* end = ptr + key_value_store_size_;
387 size_t counter = index;
388
389 while (ptr < end) {
390 // Scan for a closing zero.
391 const char* str_end = reinterpret_cast<const char*>(memchr(ptr, 0, end - ptr));
392 if (UNLIKELY(str_end == nullptr)) {
393 LOG(WARNING) << "OatHeader: Unterminated key in key value store.";
394 return false;
395 }
396 const char* value_start = str_end + 1;
397 const char* value_end =
398 reinterpret_cast<const char*>(memchr(value_start, 0, end - value_start));
399 if (UNLIKELY(value_end == nullptr)) {
400 LOG(WARNING) << "OatHeader: Unterminated value in key value store.";
401 return false;
402 }
403 if (counter == 0) {
404 *key = ptr;
405 *value = value_start;
406 return true;
407 } else {
408 --counter;
409 }
410 // Advance over the value.
411 ptr = value_end + 1;
412 }
413 // Not found.
414 return false;
415 }
416
GetHeaderSize() const417 size_t OatHeader::GetHeaderSize() const {
418 return sizeof(OatHeader) + key_value_store_size_;
419 }
420
IsDebuggable() const421 bool OatHeader::IsDebuggable() const {
422 return IsKeyEnabled(OatHeader::kDebuggableKey);
423 }
424
IsConcurrentCopying() const425 bool OatHeader::IsConcurrentCopying() const {
426 return IsKeyEnabled(OatHeader::kConcurrentCopying);
427 }
428
IsNativeDebuggable() const429 bool OatHeader::IsNativeDebuggable() const {
430 return IsKeyEnabled(OatHeader::kNativeDebuggableKey);
431 }
432
RequiresImage() const433 bool OatHeader::RequiresImage() const {
434 return IsKeyEnabled(OatHeader::kRequiresImage);
435 }
436
GetCompilerFilter() const437 CompilerFilter::Filter OatHeader::GetCompilerFilter() const {
438 CompilerFilter::Filter filter;
439 const char* key_value = GetStoreValueByKey(kCompilerFilter);
440 CHECK(key_value != nullptr) << "compiler-filter not found in oat header";
441 CHECK(CompilerFilter::ParseCompilerFilter(key_value, &filter))
442 << "Invalid compiler-filter in oat header: " << key_value;
443 return filter;
444 }
445
KeyHasValue(const char * key,const char * value,size_t value_size) const446 bool OatHeader::KeyHasValue(const char* key, const char* value, size_t value_size) const {
447 const char* key_value = GetStoreValueByKey(key);
448 return (key_value != nullptr && strncmp(key_value, value, value_size) == 0);
449 }
450
IsKeyEnabled(const char * key) const451 bool OatHeader::IsKeyEnabled(const char* key) const {
452 return KeyHasValue(key, kTrueValue, sizeof(kTrueValue));
453 }
454
Flatten(const SafeMap<std::string,std::string> * key_value_store)455 void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store) {
456 char* data_ptr = reinterpret_cast<char*>(&key_value_store_);
457 if (key_value_store != nullptr) {
458 SafeMap<std::string, std::string>::const_iterator it = key_value_store->begin();
459 SafeMap<std::string, std::string>::const_iterator end = key_value_store->end();
460 for ( ; it != end; ++it) {
461 strlcpy(data_ptr, it->first.c_str(), it->first.length() + 1);
462 data_ptr += it->first.length() + 1;
463 strlcpy(data_ptr, it->second.c_str(), it->second.length() + 1);
464 data_ptr += it->second.length() + 1;
465 }
466 }
467 key_value_store_size_ = data_ptr - reinterpret_cast<char*>(&key_value_store_);
468 }
469
GetOatAddress(StubType type) const470 const uint8_t* OatHeader::GetOatAddress(StubType type) const {
471 DCHECK_LE(type, StubType::kLast);
472 switch (type) {
473 // TODO: We could maybe clean this up if we stored them in an array in the oat header.
474 case StubType::kQuickGenericJNITrampoline:
475 return static_cast<const uint8_t*>(GetQuickGenericJniTrampoline());
476 case StubType::kJNIDlsymLookupTrampoline:
477 return static_cast<const uint8_t*>(GetJniDlsymLookupTrampoline());
478 case StubType::kJNIDlsymLookupCriticalTrampoline:
479 return static_cast<const uint8_t*>(GetJniDlsymLookupCriticalTrampoline());
480 case StubType::kQuickIMTConflictTrampoline:
481 return static_cast<const uint8_t*>(GetQuickImtConflictTrampoline());
482 case StubType::kQuickResolutionTrampoline:
483 return static_cast<const uint8_t*>(GetQuickResolutionTrampoline());
484 case StubType::kQuickToInterpreterBridge:
485 return static_cast<const uint8_t*>(GetQuickToInterpreterBridge());
486 case StubType::kNterpTrampoline:
487 return static_cast<const uint8_t*>(GetNterpTrampoline());
488 default:
489 UNREACHABLE();
490 }
491 }
492
493 } // namespace art
494