• 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 #include <zlib.h>
21 
22 #include "android-base/stringprintf.h"
23 
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 uint8_t OatHeader::kOatMagic[4];
33 constexpr uint8_t OatHeader::kOatVersion[4];
34 constexpr const char OatHeader::kTrueValue[];
35 constexpr const char OatHeader::kFalseValue[];
36 
ComputeOatHeaderSize(const SafeMap<std::string,std::string> * variable_data)37 static size_t ComputeOatHeaderSize(const SafeMap<std::string, std::string>* variable_data) {
38   size_t estimate = 0U;
39   if (variable_data != nullptr) {
40     SafeMap<std::string, std::string>::const_iterator it = variable_data->begin();
41     SafeMap<std::string, std::string>::const_iterator end = variable_data->end();
42     for ( ; it != end; ++it) {
43       estimate += it->first.length() + 1;
44       estimate += it->second.length() + 1;
45     }
46   }
47   return sizeof(OatHeader) + estimate;
48 }
49 
Create(InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,uint32_t dex_file_count,const SafeMap<std::string,std::string> * variable_data)50 OatHeader* OatHeader::Create(InstructionSet instruction_set,
51                              const InstructionSetFeatures* instruction_set_features,
52                              uint32_t dex_file_count,
53                              const SafeMap<std::string, std::string>* variable_data) {
54   // Estimate size of optional data.
55   size_t needed_size = ComputeOatHeaderSize(variable_data);
56 
57   // Reserve enough memory.
58   void* memory = operator new (needed_size);
59 
60   // Create the OatHeader in-place.
61   return new (memory) OatHeader(instruction_set,
62                                 instruction_set_features,
63                                 dex_file_count,
64                                 variable_data);
65 }
66 
OatHeader(InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,uint32_t dex_file_count,const SafeMap<std::string,std::string> * variable_data)67 OatHeader::OatHeader(InstructionSet instruction_set,
68                      const InstructionSetFeatures* instruction_set_features,
69                      uint32_t dex_file_count,
70                      const SafeMap<std::string, std::string>* variable_data)
71     : adler32_checksum_(adler32(0L, Z_NULL, 0)),
72       instruction_set_(instruction_set),
73       instruction_set_features_bitmap_(instruction_set_features->AsBitmap()),
74       dex_file_count_(dex_file_count),
75       oat_dex_files_offset_(0),
76       executable_offset_(0),
77       interpreter_to_interpreter_bridge_offset_(0),
78       interpreter_to_compiled_code_bridge_offset_(0),
79       jni_dlsym_lookup_offset_(0),
80       quick_generic_jni_trampoline_offset_(0),
81       quick_imt_conflict_trampoline_offset_(0),
82       quick_resolution_trampoline_offset_(0),
83       quick_to_interpreter_bridge_offset_(0),
84       image_patch_delta_(0),
85       image_file_location_oat_checksum_(0),
86       image_file_location_oat_data_begin_(0) {
87   // Don't want asserts in header as they would be checked in each file that includes it. But the
88   // fields are private, so we check inside a method.
89   static_assert(sizeof(magic_) == sizeof(kOatMagic),
90                 "Oat magic and magic_ have different lengths.");
91   static_assert(sizeof(version_) == sizeof(kOatVersion),
92                 "Oat version and version_ have different lengths.");
93 
94   memcpy(magic_, kOatMagic, sizeof(kOatMagic));
95   memcpy(version_, kOatVersion, sizeof(kOatVersion));
96 
97   CHECK_NE(instruction_set, kNone);
98 
99   // Flatten the map. Will also update variable_size_data_size_.
100   Flatten(variable_data);
101 }
102 
IsValid() const103 bool OatHeader::IsValid() const {
104   if (memcmp(magic_, kOatMagic, sizeof(kOatMagic)) != 0) {
105     return false;
106   }
107   if (memcmp(version_, kOatVersion, sizeof(kOatVersion)) != 0) {
108     return false;
109   }
110   if (!IsAligned<kPageSize>(executable_offset_)) {
111     return false;
112   }
113   if (!IsAligned<kPageSize>(image_patch_delta_)) {
114     return false;
115   }
116   if (!IsValidInstructionSet(instruction_set_)) {
117     return false;
118   }
119   return true;
120 }
121 
GetValidationErrorMessage() const122 std::string OatHeader::GetValidationErrorMessage() const {
123   if (memcmp(magic_, kOatMagic, sizeof(kOatMagic)) != 0) {
124     static_assert(sizeof(kOatMagic) == 4, "kOatMagic has unexpected length");
125     return StringPrintf("Invalid oat magic, expected 0x%x%x%x%x, got 0x%x%x%x%x.",
126                         kOatMagic[0], kOatMagic[1], kOatMagic[2], kOatMagic[3],
127                         magic_[0], magic_[1], magic_[2], magic_[3]);
128   }
129   if (memcmp(version_, kOatVersion, sizeof(kOatVersion)) != 0) {
130     static_assert(sizeof(kOatVersion) == 4, "kOatVersion has unexpected length");
131     return StringPrintf("Invalid oat version, expected 0x%x%x%x%x, got 0x%x%x%x%x.",
132                         kOatVersion[0], kOatVersion[1], kOatVersion[2], kOatVersion[3],
133                         version_[0], version_[1], version_[2], version_[3]);
134   }
135   if (!IsAligned<kPageSize>(executable_offset_)) {
136     return "Executable offset not page-aligned.";
137   }
138   if (!IsAligned<kPageSize>(image_patch_delta_)) {
139     return "Image patch delta not page-aligned.";
140   }
141   if (!IsValidInstructionSet(instruction_set_)) {
142     return StringPrintf("Invalid instruction set, %d.", static_cast<int>(instruction_set_));
143   }
144   return "";
145 }
146 
GetMagic() const147 const char* OatHeader::GetMagic() const {
148   CHECK(IsValid());
149   return reinterpret_cast<const char*>(magic_);
150 }
151 
GetChecksum() const152 uint32_t OatHeader::GetChecksum() const {
153   CHECK(IsValid());
154   return adler32_checksum_;
155 }
156 
UpdateChecksumWithHeaderData()157 void OatHeader::UpdateChecksumWithHeaderData() {
158   UpdateChecksum(&instruction_set_, sizeof(instruction_set_));
159   UpdateChecksum(&instruction_set_features_bitmap_, sizeof(instruction_set_features_bitmap_));
160   UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));
161   UpdateChecksum(&image_file_location_oat_checksum_, sizeof(image_file_location_oat_checksum_));
162   UpdateChecksum(&image_file_location_oat_data_begin_, sizeof(image_file_location_oat_data_begin_));
163 
164   // Update checksum for variable data size.
165   UpdateChecksum(&key_value_store_size_, sizeof(key_value_store_size_));
166 
167   // Update for data, if existing.
168   if (key_value_store_size_ > 0U) {
169     UpdateChecksum(&key_value_store_, key_value_store_size_);
170   }
171 
172   UpdateChecksum(&executable_offset_, sizeof(executable_offset_));
173   UpdateChecksum(&interpreter_to_interpreter_bridge_offset_,
174                  sizeof(interpreter_to_interpreter_bridge_offset_));
175   UpdateChecksum(&interpreter_to_compiled_code_bridge_offset_,
176                  sizeof(interpreter_to_compiled_code_bridge_offset_));
177   UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(jni_dlsym_lookup_offset_));
178   UpdateChecksum(&quick_generic_jni_trampoline_offset_,
179                  sizeof(quick_generic_jni_trampoline_offset_));
180   UpdateChecksum(&quick_imt_conflict_trampoline_offset_,
181                  sizeof(quick_imt_conflict_trampoline_offset_));
182   UpdateChecksum(&quick_resolution_trampoline_offset_,
183                  sizeof(quick_resolution_trampoline_offset_));
184   UpdateChecksum(&quick_to_interpreter_bridge_offset_,
185                  sizeof(quick_to_interpreter_bridge_offset_));
186 }
187 
UpdateChecksum(const void * data,size_t length)188 void OatHeader::UpdateChecksum(const void* data, size_t length) {
189   DCHECK(IsValid());
190   if (data != nullptr) {
191     const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
192     adler32_checksum_ = adler32(adler32_checksum_, bytes, length);
193   } else {
194     DCHECK_EQ(0U, length);
195   }
196 }
197 
GetInstructionSet() const198 InstructionSet OatHeader::GetInstructionSet() const {
199   CHECK(IsValid());
200   return instruction_set_;
201 }
202 
GetInstructionSetFeaturesBitmap() const203 uint32_t OatHeader::GetInstructionSetFeaturesBitmap() const {
204   CHECK(IsValid());
205   return instruction_set_features_bitmap_;
206 }
207 
GetOatDexFilesOffset() const208 uint32_t OatHeader::GetOatDexFilesOffset() const {
209   DCHECK(IsValid());
210   DCHECK_GT(oat_dex_files_offset_, sizeof(OatHeader));
211   return oat_dex_files_offset_;
212 }
213 
SetOatDexFilesOffset(uint32_t oat_dex_files_offset)214 void OatHeader::SetOatDexFilesOffset(uint32_t oat_dex_files_offset) {
215   DCHECK_GT(oat_dex_files_offset, sizeof(OatHeader));
216   DCHECK(IsValid());
217   DCHECK_EQ(oat_dex_files_offset_, 0u);
218 
219   oat_dex_files_offset_ = oat_dex_files_offset;
220 }
221 
GetExecutableOffset() const222 uint32_t OatHeader::GetExecutableOffset() const {
223   DCHECK(IsValid());
224   DCHECK_ALIGNED(executable_offset_, kPageSize);
225   CHECK_GT(executable_offset_, sizeof(OatHeader));
226   return executable_offset_;
227 }
228 
SetExecutableOffset(uint32_t executable_offset)229 void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
230   DCHECK_ALIGNED(executable_offset, kPageSize);
231   CHECK_GT(executable_offset, sizeof(OatHeader));
232   DCHECK(IsValid());
233   DCHECK_EQ(executable_offset_, 0U);
234 
235   executable_offset_ = executable_offset;
236 }
237 
GetInterpreterToInterpreterBridge() const238 const void* OatHeader::GetInterpreterToInterpreterBridge() const {
239   return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToInterpreterBridgeOffset();
240 }
241 
GetInterpreterToInterpreterBridgeOffset() const242 uint32_t OatHeader::GetInterpreterToInterpreterBridgeOffset() const {
243   DCHECK(IsValid());
244   CHECK(interpreter_to_interpreter_bridge_offset_ == 0 ||
245         interpreter_to_interpreter_bridge_offset_ >= executable_offset_);
246   return interpreter_to_interpreter_bridge_offset_;
247 }
248 
SetInterpreterToInterpreterBridgeOffset(uint32_t offset)249 void OatHeader::SetInterpreterToInterpreterBridgeOffset(uint32_t offset) {
250   CHECK(offset == 0 || offset >= executable_offset_);
251   DCHECK(IsValid());
252   DCHECK_EQ(interpreter_to_interpreter_bridge_offset_, 0U) << offset;
253 
254   interpreter_to_interpreter_bridge_offset_ = offset;
255 }
256 
GetInterpreterToCompiledCodeBridge() const257 const void* OatHeader::GetInterpreterToCompiledCodeBridge() const {
258   return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToCompiledCodeBridgeOffset();
259 }
260 
GetInterpreterToCompiledCodeBridgeOffset() const261 uint32_t OatHeader::GetInterpreterToCompiledCodeBridgeOffset() const {
262   DCHECK(IsValid());
263   CHECK_GE(interpreter_to_compiled_code_bridge_offset_, interpreter_to_interpreter_bridge_offset_);
264   return interpreter_to_compiled_code_bridge_offset_;
265 }
266 
SetInterpreterToCompiledCodeBridgeOffset(uint32_t offset)267 void OatHeader::SetInterpreterToCompiledCodeBridgeOffset(uint32_t offset) {
268   CHECK(offset == 0 || offset >= interpreter_to_interpreter_bridge_offset_);
269   DCHECK(IsValid());
270   DCHECK_EQ(interpreter_to_compiled_code_bridge_offset_, 0U) << offset;
271 
272   interpreter_to_compiled_code_bridge_offset_ = offset;
273 }
274 
GetJniDlsymLookup() const275 const void* OatHeader::GetJniDlsymLookup() const {
276   return reinterpret_cast<const uint8_t*>(this) + GetJniDlsymLookupOffset();
277 }
278 
GetJniDlsymLookupOffset() const279 uint32_t OatHeader::GetJniDlsymLookupOffset() const {
280   DCHECK(IsValid());
281   CHECK_GE(jni_dlsym_lookup_offset_, interpreter_to_compiled_code_bridge_offset_);
282   return jni_dlsym_lookup_offset_;
283 }
284 
SetJniDlsymLookupOffset(uint32_t offset)285 void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) {
286   CHECK(offset == 0 || offset >= interpreter_to_compiled_code_bridge_offset_);
287   DCHECK(IsValid());
288   DCHECK_EQ(jni_dlsym_lookup_offset_, 0U) << offset;
289 
290   jni_dlsym_lookup_offset_ = offset;
291 }
292 
GetQuickGenericJniTrampoline() const293 const void* OatHeader::GetQuickGenericJniTrampoline() const {
294   return reinterpret_cast<const uint8_t*>(this) + GetQuickGenericJniTrampolineOffset();
295 }
296 
GetQuickGenericJniTrampolineOffset() const297 uint32_t OatHeader::GetQuickGenericJniTrampolineOffset() const {
298   DCHECK(IsValid());
299   CHECK_GE(quick_generic_jni_trampoline_offset_, jni_dlsym_lookup_offset_);
300   return quick_generic_jni_trampoline_offset_;
301 }
302 
SetQuickGenericJniTrampolineOffset(uint32_t offset)303 void OatHeader::SetQuickGenericJniTrampolineOffset(uint32_t offset) {
304   CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_);
305   DCHECK(IsValid());
306   DCHECK_EQ(quick_generic_jni_trampoline_offset_, 0U) << offset;
307 
308   quick_generic_jni_trampoline_offset_ = offset;
309 }
310 
GetQuickImtConflictTrampoline() const311 const void* OatHeader::GetQuickImtConflictTrampoline() const {
312   return reinterpret_cast<const uint8_t*>(this) + GetQuickImtConflictTrampolineOffset();
313 }
314 
GetQuickImtConflictTrampolineOffset() const315 uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const {
316   DCHECK(IsValid());
317   CHECK_GE(quick_imt_conflict_trampoline_offset_, quick_generic_jni_trampoline_offset_);
318   return quick_imt_conflict_trampoline_offset_;
319 }
320 
SetQuickImtConflictTrampolineOffset(uint32_t offset)321 void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) {
322   CHECK(offset == 0 || offset >= quick_generic_jni_trampoline_offset_);
323   DCHECK(IsValid());
324   DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset;
325 
326   quick_imt_conflict_trampoline_offset_ = offset;
327 }
328 
GetQuickResolutionTrampoline() const329 const void* OatHeader::GetQuickResolutionTrampoline() const {
330   return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset();
331 }
332 
GetQuickResolutionTrampolineOffset() const333 uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
334   DCHECK(IsValid());
335   CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_);
336   return quick_resolution_trampoline_offset_;
337 }
338 
SetQuickResolutionTrampolineOffset(uint32_t offset)339 void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
340   CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_);
341   DCHECK(IsValid());
342   DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;
343 
344   quick_resolution_trampoline_offset_ = offset;
345 }
346 
GetQuickToInterpreterBridge() const347 const void* OatHeader::GetQuickToInterpreterBridge() const {
348   return reinterpret_cast<const uint8_t*>(this) + GetQuickToInterpreterBridgeOffset();
349 }
350 
GetQuickToInterpreterBridgeOffset() const351 uint32_t OatHeader::GetQuickToInterpreterBridgeOffset() const {
352   DCHECK(IsValid());
353   CHECK_GE(quick_to_interpreter_bridge_offset_, quick_resolution_trampoline_offset_);
354   return quick_to_interpreter_bridge_offset_;
355 }
356 
SetQuickToInterpreterBridgeOffset(uint32_t offset)357 void OatHeader::SetQuickToInterpreterBridgeOffset(uint32_t offset) {
358   CHECK(offset == 0 || offset >= quick_resolution_trampoline_offset_);
359   DCHECK(IsValid());
360   DCHECK_EQ(quick_to_interpreter_bridge_offset_, 0U) << offset;
361 
362   quick_to_interpreter_bridge_offset_ = offset;
363 }
364 
GetImagePatchDelta() const365 int32_t OatHeader::GetImagePatchDelta() const {
366   CHECK(IsValid());
367   return image_patch_delta_;
368 }
369 
RelocateOat(off_t delta)370 void OatHeader::RelocateOat(off_t delta) {
371   CHECK(IsValid());
372   CHECK_ALIGNED(delta, kPageSize);
373   image_patch_delta_ += delta;
374   if (image_file_location_oat_data_begin_ != 0) {
375     image_file_location_oat_data_begin_ += delta;
376   }
377 }
378 
SetImagePatchDelta(int32_t off)379 void OatHeader::SetImagePatchDelta(int32_t off) {
380   CHECK(IsValid());
381   CHECK_ALIGNED(off, kPageSize);
382   image_patch_delta_ = off;
383 }
384 
GetImageFileLocationOatChecksum() const385 uint32_t OatHeader::GetImageFileLocationOatChecksum() const {
386   CHECK(IsValid());
387   return image_file_location_oat_checksum_;
388 }
389 
SetImageFileLocationOatChecksum(uint32_t image_file_location_oat_checksum)390 void OatHeader::SetImageFileLocationOatChecksum(uint32_t image_file_location_oat_checksum) {
391   CHECK(IsValid());
392   image_file_location_oat_checksum_ = image_file_location_oat_checksum;
393 }
394 
GetImageFileLocationOatDataBegin() const395 uint32_t OatHeader::GetImageFileLocationOatDataBegin() const {
396   CHECK(IsValid());
397   return image_file_location_oat_data_begin_;
398 }
399 
SetImageFileLocationOatDataBegin(uint32_t image_file_location_oat_data_begin)400 void OatHeader::SetImageFileLocationOatDataBegin(uint32_t image_file_location_oat_data_begin) {
401   CHECK(IsValid());
402   CHECK_ALIGNED(image_file_location_oat_data_begin, kPageSize);
403   image_file_location_oat_data_begin_ = image_file_location_oat_data_begin;
404 }
405 
GetKeyValueStoreSize() const406 uint32_t OatHeader::GetKeyValueStoreSize() const {
407   CHECK(IsValid());
408   return key_value_store_size_;
409 }
410 
GetKeyValueStore() const411 const uint8_t* OatHeader::GetKeyValueStore() const {
412   CHECK(IsValid());
413   return key_value_store_;
414 }
415 
416 // Advance start until it is either end or \0.
ParseString(const char * start,const char * end)417 static const char* ParseString(const char* start, const char* end) {
418   while (start < end && *start != 0) {
419     start++;
420   }
421   return start;
422 }
423 
GetStoreValueByKey(const char * key) const424 const char* OatHeader::GetStoreValueByKey(const char* key) const {
425   const char* ptr = reinterpret_cast<const char*>(&key_value_store_);
426   const char* end = ptr + key_value_store_size_;
427 
428   while (ptr < end) {
429     // Scan for a closing zero.
430     const char* str_end = ParseString(ptr, end);
431     if (str_end < end) {
432       if (strcmp(key, ptr) == 0) {
433         // Same as key. Check if value is OK.
434         if (ParseString(str_end + 1, end) < end) {
435           return str_end + 1;
436         }
437       } else {
438         // Different from key. Advance over the value.
439         ptr = ParseString(str_end + 1, end) + 1;
440       }
441     } else {
442       break;
443     }
444   }
445   // Not found.
446   return nullptr;
447 }
448 
GetStoreKeyValuePairByIndex(size_t index,const char ** key,const char ** value) const449 bool OatHeader::GetStoreKeyValuePairByIndex(size_t index, const char** key,
450                                             const char** value) const {
451   const char* ptr = reinterpret_cast<const char*>(&key_value_store_);
452   const char* end = ptr + key_value_store_size_;
453   ssize_t counter = static_cast<ssize_t>(index);
454 
455   while (ptr < end && counter >= 0) {
456     // Scan for a closing zero.
457     const char* str_end = ParseString(ptr, end);
458     if (str_end < end) {
459       const char* maybe_key = ptr;
460       ptr = ParseString(str_end + 1, end) + 1;
461       if (ptr <= end) {
462         if (counter == 0) {
463           *key = maybe_key;
464           *value = str_end + 1;
465           return true;
466         } else {
467           counter--;
468         }
469       } else {
470         return false;
471       }
472     } else {
473       break;
474     }
475   }
476   // Not found.
477   return false;
478 }
479 
GetHeaderSize() const480 size_t OatHeader::GetHeaderSize() const {
481   return sizeof(OatHeader) + key_value_store_size_;
482 }
483 
IsPic() const484 bool OatHeader::IsPic() const {
485   return IsKeyEnabled(OatHeader::kPicKey);
486 }
487 
IsDebuggable() const488 bool OatHeader::IsDebuggable() const {
489   return IsKeyEnabled(OatHeader::kDebuggableKey);
490 }
491 
IsConcurrentCopying() const492 bool OatHeader::IsConcurrentCopying() const {
493   return IsKeyEnabled(OatHeader::kConcurrentCopying);
494 }
495 
IsNativeDebuggable() const496 bool OatHeader::IsNativeDebuggable() const {
497   return IsKeyEnabled(OatHeader::kNativeDebuggableKey);
498 }
499 
GetCompilerFilter() const500 CompilerFilter::Filter OatHeader::GetCompilerFilter() const {
501   CompilerFilter::Filter filter;
502   const char* key_value = GetStoreValueByKey(kCompilerFilter);
503   CHECK(key_value != nullptr) << "compiler-filter not found in oat header";
504   CHECK(CompilerFilter::ParseCompilerFilter(key_value, &filter))
505       << "Invalid compiler-filter in oat header: " << key_value;
506   return filter;
507 }
508 
KeyHasValue(const char * key,const char * value,size_t value_size) const509 bool OatHeader::KeyHasValue(const char* key, const char* value, size_t value_size) const {
510   const char* key_value = GetStoreValueByKey(key);
511   return (key_value != nullptr && strncmp(key_value, value, value_size) == 0);
512 }
513 
IsKeyEnabled(const char * key) const514 bool OatHeader::IsKeyEnabled(const char* key) const {
515   return KeyHasValue(key, kTrueValue, sizeof(kTrueValue));
516 }
517 
Flatten(const SafeMap<std::string,std::string> * key_value_store)518 void OatHeader::Flatten(const SafeMap<std::string, std::string>* key_value_store) {
519   char* data_ptr = reinterpret_cast<char*>(&key_value_store_);
520   if (key_value_store != nullptr) {
521     SafeMap<std::string, std::string>::const_iterator it = key_value_store->begin();
522     SafeMap<std::string, std::string>::const_iterator end = key_value_store->end();
523     for ( ; it != end; ++it) {
524       strlcpy(data_ptr, it->first.c_str(), it->first.length() + 1);
525       data_ptr += it->first.length() + 1;
526       strlcpy(data_ptr, it->second.c_str(), it->second.length() + 1);
527       data_ptr += it->second.length() + 1;
528     }
529   }
530   key_value_store_size_ = data_ptr - reinterpret_cast<char*>(&key_value_store_);
531 }
532 
OatMethodOffsets(uint32_t code_offset)533 OatMethodOffsets::OatMethodOffsets(uint32_t code_offset) : code_offset_(code_offset) {
534 }
535 
~OatMethodOffsets()536 OatMethodOffsets::~OatMethodOffsets() {}
537 
538 }  // namespace art
539