Home | History | Annotate | Download | only in runtime
      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_file.h"
     18 
     19 #include <dlfcn.h>
     20 #include <sstream>
     21 #include <string.h>
     22 #include <unistd.h>
     23 
     24 #include "base/bit_vector.h"
     25 #include "base/stl_util.h"
     26 #include "base/unix_file/fd_file.h"
     27 #include "elf_file.h"
     28 #include "elf_utils.h"
     29 #include "oat.h"
     30 #include "mirror/art_method.h"
     31 #include "mirror/art_method-inl.h"
     32 #include "mirror/class.h"
     33 #include "mirror/object-inl.h"
     34 #include "os.h"
     35 #include "runtime.h"
     36 #include "utils.h"
     37 #include "vmap_table.h"
     38 
     39 namespace art {
     40 
     41 void OatFile::CheckLocation(const std::string& location) {
     42   CHECK(!location.empty());
     43 }
     44 
     45 OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file,
     46                                   const std::string& location,
     47                                   std::string* error_msg) {
     48   std::unique_ptr<OatFile> oat_file(new OatFile(location, false));
     49   oat_file->elf_file_.reset(elf_file);
     50   Elf32_Shdr* hdr = elf_file->FindSectionByName(".rodata");
     51   oat_file->begin_ = elf_file->Begin() + hdr->sh_offset;
     52   oat_file->end_ = elf_file->Begin() + hdr->sh_size + hdr->sh_offset;
     53   return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
     54 }
     55 
     56 OatFile* OatFile::OpenMemory(std::vector<uint8_t>& oat_contents,
     57                              const std::string& location,
     58                              std::string* error_msg) {
     59   CHECK(!oat_contents.empty()) << location;
     60   CheckLocation(location);
     61   std::unique_ptr<OatFile> oat_file(new OatFile(location, false));
     62   oat_file->begin_ = &oat_contents[0];
     63   oat_file->end_ = &oat_contents[oat_contents.size()];
     64   return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
     65 }
     66 
     67 OatFile* OatFile::Open(const std::string& filename,
     68                        const std::string& location,
     69                        byte* requested_base,
     70                        uint8_t* oat_file_begin,
     71                        bool executable,
     72                        std::string* error_msg) {
     73   CHECK(!filename.empty()) << location;
     74   CheckLocation(location);
     75   std::unique_ptr<OatFile> ret;
     76   if (kUsePortableCompiler && executable) {
     77     // If we are using PORTABLE, use dlopen to deal with relocations.
     78     //
     79     // We use our own ELF loader for Quick to deal with legacy apps that
     80     // open a generated dex file by name, remove the file, then open
     81     // another generated dex file with the same name. http://b/10614658
     82     ret.reset(OpenDlopen(filename, location, requested_base, error_msg));
     83   } else {
     84     // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
     85     //
     86     // On target, dlopen may fail when compiling due to selinux restrictions on installd.
     87     //
     88     // On host, dlopen is expected to fail when cross compiling, so fall back to OpenElfFile.
     89     // This won't work for portable runtime execution because it doesn't process relocations.
     90     std::unique_ptr<File> file(OS::OpenFileForReading(filename.c_str()));
     91     if (file.get() == NULL) {
     92       *error_msg = StringPrintf("Failed to open oat filename for reading: %s", strerror(errno));
     93       return nullptr;
     94     }
     95     ret.reset(OpenElfFile(file.get(), location, requested_base, oat_file_begin, false, executable,
     96                           error_msg));
     97 
     98     // It would be nice to unlink here. But we might have opened the file created by the
     99     // ScopedLock, which we better not delete to avoid races. TODO: Investigate how to fix the API
    100     // to allow removal when we know the ELF must be borked.
    101   }
    102   return ret.release();
    103 }
    104 
    105 OatFile* OatFile::OpenWritable(File* file, const std::string& location, std::string* error_msg) {
    106   CheckLocation(location);
    107   return OpenElfFile(file, location, nullptr, nullptr, true, false, error_msg);
    108 }
    109 
    110 OatFile* OatFile::OpenReadable(File* file, const std::string& location, std::string* error_msg) {
    111   CheckLocation(location);
    112   return OpenElfFile(file, location, nullptr, nullptr, false, false, error_msg);
    113 }
    114 
    115 OatFile* OatFile::OpenDlopen(const std::string& elf_filename,
    116                              const std::string& location,
    117                              byte* requested_base,
    118                              std::string* error_msg) {
    119   std::unique_ptr<OatFile> oat_file(new OatFile(location, true));
    120   bool success = oat_file->Dlopen(elf_filename, requested_base, error_msg);
    121   if (!success) {
    122     return nullptr;
    123   }
    124   return oat_file.release();
    125 }
    126 
    127 OatFile* OatFile::OpenElfFile(File* file,
    128                               const std::string& location,
    129                               byte* requested_base,
    130                               uint8_t* oat_file_begin,
    131                               bool writable,
    132                               bool executable,
    133                               std::string* error_msg) {
    134   std::unique_ptr<OatFile> oat_file(new OatFile(location, executable));
    135   bool success = oat_file->ElfFileOpen(file, requested_base, oat_file_begin, writable, executable,
    136                                        error_msg);
    137   if (!success) {
    138     CHECK(!error_msg->empty());
    139     return nullptr;
    140   }
    141   return oat_file.release();
    142 }
    143 
    144 OatFile::OatFile(const std::string& location, bool is_executable)
    145     : location_(location), begin_(NULL), end_(NULL), is_executable_(is_executable),
    146       dlopen_handle_(NULL),
    147       secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
    148   CHECK(!location_.empty());
    149 }
    150 
    151 OatFile::~OatFile() {
    152   STLDeleteElements(&oat_dex_files_storage_);
    153   if (dlopen_handle_ != NULL) {
    154     dlclose(dlopen_handle_);
    155   }
    156 }
    157 
    158 bool OatFile::Dlopen(const std::string& elf_filename, byte* requested_base,
    159                      std::string* error_msg) {
    160   char* absolute_path = realpath(elf_filename.c_str(), NULL);
    161   if (absolute_path == NULL) {
    162     *error_msg = StringPrintf("Failed to find absolute path for '%s'", elf_filename.c_str());
    163     return false;
    164   }
    165   dlopen_handle_ = dlopen(absolute_path, RTLD_NOW);
    166   free(absolute_path);
    167   if (dlopen_handle_ == NULL) {
    168     *error_msg = StringPrintf("Failed to dlopen '%s': %s", elf_filename.c_str(), dlerror());
    169     return false;
    170   }
    171   begin_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatdata"));
    172   if (begin_ == NULL) {
    173     *error_msg = StringPrintf("Failed to find oatdata symbol in '%s': %s", elf_filename.c_str(),
    174                               dlerror());
    175     return false;
    176   }
    177   if (requested_base != NULL && begin_ != requested_base) {
    178     *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
    179                               "oatdata=%p != expected=%p /proc/self/maps:\n",
    180                               begin_, requested_base);
    181     ReadFileToString("/proc/self/maps", error_msg);
    182     return false;
    183   }
    184   end_ = reinterpret_cast<byte*>(dlsym(dlopen_handle_, "oatlastword"));
    185   if (end_ == NULL) {
    186     *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s': %s", elf_filename.c_str(),
    187                               dlerror());
    188     return false;
    189   }
    190   // Readjust to be non-inclusive upper bound.
    191   end_ += sizeof(uint32_t);
    192   return Setup(error_msg);
    193 }
    194 
    195 bool OatFile::ElfFileOpen(File* file, byte* requested_base, uint8_t* oat_file_begin,
    196                           bool writable, bool executable,
    197                           std::string* error_msg) {
    198   // TODO: rename requested_base to oat_data_begin
    199   elf_file_.reset(ElfFile::Open(file, writable, /*program_header_only*/true, error_msg,
    200                                 oat_file_begin));
    201   if (elf_file_.get() == nullptr) {
    202     DCHECK(!error_msg->empty());
    203     return false;
    204   }
    205   bool loaded = elf_file_->Load(executable, error_msg);
    206   if (!loaded) {
    207     DCHECK(!error_msg->empty());
    208     return false;
    209   }
    210   begin_ = elf_file_->FindDynamicSymbolAddress("oatdata");
    211   if (begin_ == NULL) {
    212     *error_msg = StringPrintf("Failed to find oatdata symbol in '%s'", file->GetPath().c_str());
    213     return false;
    214   }
    215   if (requested_base != NULL && begin_ != requested_base) {
    216     *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: "
    217                               "oatdata=%p != expected=%p /proc/self/maps:\n",
    218                               begin_, requested_base);
    219     ReadFileToString("/proc/self/maps", error_msg);
    220     return false;
    221   }
    222   end_ = elf_file_->FindDynamicSymbolAddress("oatlastword");
    223   if (end_ == NULL) {
    224     *error_msg = StringPrintf("Failed to find oatlastword symbol in '%s'", file->GetPath().c_str());
    225     return false;
    226   }
    227   // Readjust to be non-inclusive upper bound.
    228   end_ += sizeof(uint32_t);
    229   return Setup(error_msg);
    230 }
    231 
    232 bool OatFile::Setup(std::string* error_msg) {
    233   if (!GetOatHeader().IsValid()) {
    234     *error_msg = StringPrintf("Invalid oat magic for '%s'", GetLocation().c_str());
    235     return false;
    236   }
    237   const byte* oat = Begin();
    238   oat += sizeof(OatHeader);
    239   if (oat > End()) {
    240     *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader", GetLocation().c_str());
    241     return false;
    242   }
    243 
    244   oat += GetOatHeader().GetKeyValueStoreSize();
    245   if (oat > End()) {
    246     *error_msg = StringPrintf("In oat file '%s' found truncated variable-size data: "
    247                               "%p + %zd + %ud <= %p", GetLocation().c_str(),
    248                               Begin(), sizeof(OatHeader), GetOatHeader().GetKeyValueStoreSize(),
    249                               End());
    250     return false;
    251   }
    252 
    253   uint32_t dex_file_count = GetOatHeader().GetDexFileCount();
    254   oat_dex_files_storage_.reserve(dex_file_count);
    255   for (size_t i = 0; i < dex_file_count; i++) {
    256     uint32_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
    257     if (UNLIKELY(dex_file_location_size == 0U)) {
    258       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name",
    259                                 GetLocation().c_str(), i);
    260       return false;
    261     }
    262     oat += sizeof(dex_file_location_size);
    263     if (UNLIKELY(oat > End())) {
    264       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd truncated after dex file "
    265                                 "location size", GetLocation().c_str(), i);
    266       return false;
    267     }
    268 
    269     const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
    270     oat += dex_file_location_size;
    271     if (UNLIKELY(oat > End())) {
    272       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with truncated dex file "
    273                                 "location", GetLocation().c_str(), i);
    274       return false;
    275     }
    276 
    277     std::string dex_file_location(dex_file_location_data, dex_file_location_size);
    278 
    279     uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
    280     oat += sizeof(dex_file_checksum);
    281     if (UNLIKELY(oat > End())) {
    282       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated after "
    283                                 "dex file checksum", GetLocation().c_str(), i,
    284                                 dex_file_location.c_str());
    285       return false;
    286     }
    287 
    288     uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat);
    289     if (UNLIKELY(dex_file_offset == 0U)) {
    290       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with zero dex "
    291                                 "file offset", GetLocation().c_str(), i, dex_file_location.c_str());
    292       return false;
    293     }
    294     if (UNLIKELY(dex_file_offset > Size())) {
    295       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with dex file "
    296                                 "offset %ud > %zd", GetLocation().c_str(), i,
    297                                 dex_file_location.c_str(), dex_file_offset, Size());
    298       return false;
    299     }
    300     oat += sizeof(dex_file_offset);
    301     if (UNLIKELY(oat > End())) {
    302       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated "
    303                                 " after dex file offsets", GetLocation().c_str(), i,
    304                                 dex_file_location.c_str());
    305       return false;
    306     }
    307 
    308     const uint8_t* dex_file_pointer = Begin() + dex_file_offset;
    309     if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) {
    310       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
    311                                 " dex file magic '%s'", GetLocation().c_str(), i,
    312                                 dex_file_location.c_str(), dex_file_pointer);
    313       return false;
    314     }
    315     if (UNLIKELY(!DexFile::IsVersionValid(dex_file_pointer))) {
    316       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with invalid "
    317                                 " dex file version '%s'", GetLocation().c_str(), i,
    318                                 dex_file_location.c_str(), dex_file_pointer);
    319       return false;
    320     }
    321     const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer);
    322     const uint32_t* methods_offsets_pointer = reinterpret_cast<const uint32_t*>(oat);
    323 
    324     oat += (sizeof(*methods_offsets_pointer) * header->class_defs_size_);
    325     if (UNLIKELY(oat > End())) {
    326       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' with truncated "
    327                                 " method offsets", GetLocation().c_str(), i,
    328                                 dex_file_location.c_str());
    329       return false;
    330     }
    331 
    332     std::string canonical_location = DexFile::GetDexCanonicalLocation(dex_file_location.c_str());
    333 
    334     // Create the OatDexFile and add it to the owning container.
    335     OatDexFile* oat_dex_file = new OatDexFile(this,
    336                                               dex_file_location,
    337                                               canonical_location,
    338                                               dex_file_checksum,
    339                                               dex_file_pointer,
    340                                               methods_offsets_pointer);
    341     oat_dex_files_storage_.push_back(oat_dex_file);
    342 
    343     // Add the location and canonical location (if different) to the oat_dex_files_ table.
    344     StringPiece key(oat_dex_file->GetDexFileLocation());
    345     oat_dex_files_.Put(key, oat_dex_file);
    346     if (canonical_location != dex_file_location) {
    347       StringPiece canonical_key(oat_dex_file->GetCanonicalDexFileLocation());
    348       oat_dex_files_.Put(canonical_key, oat_dex_file);
    349     }
    350   }
    351   return true;
    352 }
    353 
    354 const OatHeader& OatFile::GetOatHeader() const {
    355   return *reinterpret_cast<const OatHeader*>(Begin());
    356 }
    357 
    358 const byte* OatFile::Begin() const {
    359   CHECK(begin_ != NULL);
    360   return begin_;
    361 }
    362 
    363 const byte* OatFile::End() const {
    364   CHECK(end_ != NULL);
    365   return end_;
    366 }
    367 
    368 const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
    369                                                   const uint32_t* dex_location_checksum,
    370                                                   bool warn_if_not_found) const {
    371   // NOTE: We assume here that the canonical location for a given dex_location never
    372   // changes. If it does (i.e. some symlink used by the filename changes) we may return
    373   // an incorrect OatDexFile. As long as we have a checksum to check, we shall return
    374   // an identical file or fail; otherwise we may see some unpredictable failures.
    375 
    376   // TODO: Additional analysis of usage patterns to see if this can be simplified
    377   // without any performance loss, for example by not doing the first lock-free lookup.
    378 
    379   const OatFile::OatDexFile* oat_dex_file = nullptr;
    380   StringPiece key(dex_location);
    381   // Try to find the key cheaply in the oat_dex_files_ map which holds dex locations
    382   // directly mentioned in the oat file and doesn't require locking.
    383   auto primary_it = oat_dex_files_.find(key);
    384   if (primary_it != oat_dex_files_.end()) {
    385     oat_dex_file = primary_it->second;
    386     DCHECK(oat_dex_file != nullptr);
    387   } else {
    388     // This dex_location is not one of the dex locations directly mentioned in the
    389     // oat file. The correct lookup is via the canonical location but first see in
    390     // the secondary_oat_dex_files_ whether we've looked up this location before.
    391     MutexLock mu(Thread::Current(), secondary_lookup_lock_);
    392     auto secondary_lb = secondary_oat_dex_files_.lower_bound(key);
    393     if (secondary_lb != secondary_oat_dex_files_.end() && key == secondary_lb->first) {
    394       oat_dex_file = secondary_lb->second;  // May be nullptr.
    395     } else {
    396       // We haven't seen this dex_location before, we must check the canonical location.
    397       std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
    398       if (dex_canonical_location != dex_location) {
    399         StringPiece canonical_key(dex_canonical_location);
    400         auto canonical_it = oat_dex_files_.find(canonical_key);
    401         if (canonical_it != oat_dex_files_.end()) {
    402           oat_dex_file = canonical_it->second;
    403         }  // else keep nullptr.
    404       }  // else keep nullptr.
    405 
    406       // Copy the key to the string_cache_ and store the result in secondary map.
    407       string_cache_.emplace_back(key.data(), key.length());
    408       StringPiece key_copy(string_cache_.back());
    409       secondary_oat_dex_files_.PutBefore(secondary_lb, key_copy, oat_dex_file);
    410     }
    411   }
    412   if (oat_dex_file != nullptr &&
    413       (dex_location_checksum == nullptr ||
    414        oat_dex_file->GetDexFileLocationChecksum() == *dex_location_checksum)) {
    415     return oat_dex_file;
    416   }
    417 
    418   if (warn_if_not_found) {
    419     std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
    420     std::string checksum("<unspecified>");
    421     if (dex_location_checksum != NULL) {
    422       checksum = StringPrintf("0x%08x", *dex_location_checksum);
    423     }
    424     LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_location
    425                  << " ( canonical path " << dex_canonical_location << ")"
    426                  << " with checksum " << checksum << " in OatFile " << GetLocation();
    427     if (kIsDebugBuild) {
    428       for (const OatDexFile* odf : oat_dex_files_storage_) {
    429         LOG(WARNING) << "OatFile " << GetLocation()
    430                      << " contains OatDexFile " << odf->GetDexFileLocation()
    431                      << " (canonical path " << odf->GetCanonicalDexFileLocation() << ")"
    432                      << " with checksum 0x" << std::hex << odf->GetDexFileLocationChecksum();
    433       }
    434     }
    435   }
    436 
    437   return NULL;
    438 }
    439 
    440 OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
    441                                 const std::string& dex_file_location,
    442                                 const std::string& canonical_dex_file_location,
    443                                 uint32_t dex_file_location_checksum,
    444                                 const byte* dex_file_pointer,
    445                                 const uint32_t* oat_class_offsets_pointer)
    446     : oat_file_(oat_file),
    447       dex_file_location_(dex_file_location),
    448       canonical_dex_file_location_(canonical_dex_file_location),
    449       dex_file_location_checksum_(dex_file_location_checksum),
    450       dex_file_pointer_(dex_file_pointer),
    451       oat_class_offsets_pointer_(oat_class_offsets_pointer) {}
    452 
    453 OatFile::OatDexFile::~OatDexFile() {}
    454 
    455 size_t OatFile::OatDexFile::FileSize() const {
    456   return reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_;
    457 }
    458 
    459 const DexFile* OatFile::OatDexFile::OpenDexFile(std::string* error_msg) const {
    460   return DexFile::Open(dex_file_pointer_, FileSize(), dex_file_location_,
    461                        dex_file_location_checksum_, GetOatFile(), error_msg);
    462 }
    463 
    464 uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const {
    465   return oat_class_offsets_pointer_[class_def_index];
    466 }
    467 
    468 OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const {
    469   uint32_t oat_class_offset = GetOatClassOffset(class_def_index);
    470 
    471   const byte* oat_class_pointer = oat_file_->Begin() + oat_class_offset;
    472   CHECK_LT(oat_class_pointer, oat_file_->End()) << oat_file_->GetLocation();
    473 
    474   const byte* status_pointer = oat_class_pointer;
    475   CHECK_LT(status_pointer, oat_file_->End()) << oat_file_->GetLocation();
    476   mirror::Class::Status status =
    477       static_cast<mirror::Class::Status>(*reinterpret_cast<const int16_t*>(status_pointer));
    478   CHECK_LT(status, mirror::Class::kStatusMax);
    479 
    480   const byte* type_pointer = status_pointer + sizeof(uint16_t);
    481   CHECK_LT(type_pointer, oat_file_->End()) << oat_file_->GetLocation();
    482   OatClassType type = static_cast<OatClassType>(*reinterpret_cast<const uint16_t*>(type_pointer));
    483   CHECK_LT(type, kOatClassMax);
    484 
    485   const byte* after_type_pointer = type_pointer + sizeof(int16_t);
    486   CHECK_LE(after_type_pointer, oat_file_->End()) << oat_file_->GetLocation();
    487 
    488   uint32_t bitmap_size = 0;
    489   const byte* bitmap_pointer = nullptr;
    490   const byte* methods_pointer = nullptr;
    491   if (type == kOatClassSomeCompiled) {
    492     bitmap_size = static_cast<uint32_t>(*reinterpret_cast<const uint32_t*>(after_type_pointer));
    493     bitmap_pointer = after_type_pointer + sizeof(bitmap_size);
    494     CHECK_LE(bitmap_pointer, oat_file_->End()) << oat_file_->GetLocation();
    495     methods_pointer = bitmap_pointer + bitmap_size;
    496   } else {
    497     methods_pointer = after_type_pointer;
    498   }
    499   CHECK_LE(methods_pointer, oat_file_->End()) << oat_file_->GetLocation();
    500 
    501   return OatClass(oat_file_,
    502                   status,
    503                   type,
    504                   bitmap_size,
    505                   reinterpret_cast<const uint32_t*>(bitmap_pointer),
    506                   reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
    507 }
    508 
    509 OatFile::OatClass::OatClass(const OatFile* oat_file,
    510                             mirror::Class::Status status,
    511                             OatClassType type,
    512                             uint32_t bitmap_size,
    513                             const uint32_t* bitmap_pointer,
    514                             const OatMethodOffsets* methods_pointer)
    515     : oat_file_(oat_file), status_(status), type_(type),
    516       bitmap_(bitmap_pointer), methods_pointer_(methods_pointer) {
    517     CHECK(methods_pointer != nullptr);
    518     switch (type_) {
    519       case kOatClassAllCompiled: {
    520         CHECK_EQ(0U, bitmap_size);
    521         CHECK(bitmap_pointer == nullptr);
    522         break;
    523       }
    524       case kOatClassSomeCompiled: {
    525         CHECK_NE(0U, bitmap_size);
    526         CHECK(bitmap_pointer != nullptr);
    527         break;
    528       }
    529       case kOatClassNoneCompiled: {
    530         CHECK_EQ(0U, bitmap_size);
    531         CHECK(bitmap_pointer == nullptr);
    532         methods_pointer_ = nullptr;
    533         break;
    534       }
    535       case kOatClassMax: {
    536         LOG(FATAL) << "Invalid OatClassType " << type_;
    537         break;
    538       }
    539     }
    540 }
    541 
    542 uint32_t OatFile::OatClass::GetOatMethodOffsetsOffset(uint32_t method_index) const {
    543   const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index);
    544   if (oat_method_offsets == nullptr) {
    545     return 0u;
    546   }
    547   return reinterpret_cast<const uint8_t*>(oat_method_offsets) - oat_file_->Begin();
    548 }
    549 
    550 const OatMethodOffsets* OatFile::OatClass::GetOatMethodOffsets(uint32_t method_index) const {
    551   // NOTE: We don't keep the number of methods and cannot do a bounds check for method_index.
    552   if (methods_pointer_ == nullptr) {
    553     CHECK_EQ(kOatClassNoneCompiled, type_);
    554     return nullptr;
    555   }
    556   size_t methods_pointer_index;
    557   if (bitmap_ == nullptr) {
    558     CHECK_EQ(kOatClassAllCompiled, type_);
    559     methods_pointer_index = method_index;
    560   } else {
    561     CHECK_EQ(kOatClassSomeCompiled, type_);
    562     if (!BitVector::IsBitSet(bitmap_, method_index)) {
    563       return nullptr;
    564     }
    565     size_t num_set_bits = BitVector::NumSetBits(bitmap_, method_index);
    566     methods_pointer_index = num_set_bits;
    567   }
    568   const OatMethodOffsets& oat_method_offsets = methods_pointer_[methods_pointer_index];
    569   return &oat_method_offsets;
    570 }
    571 
    572 const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
    573   const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index);
    574   if (oat_method_offsets == nullptr) {
    575     return OatMethod(nullptr, 0);
    576   }
    577   if (oat_file_->IsExecutable() ||
    578       Runtime::Current() == nullptr ||        // This case applies for oatdump.
    579       Runtime::Current()->IsCompiler()) {
    580     return OatMethod(oat_file_->Begin(), oat_method_offsets->code_offset_);
    581   } else {
    582     // We aren't allowed to use the compiled code. We just force it down the interpreted version.
    583     return OatMethod(oat_file_->Begin(), 0);
    584   }
    585 }
    586 
    587 OatFile::OatMethod::OatMethod(const byte* base,
    588                               const uint32_t code_offset)
    589   : begin_(base),
    590     code_offset_(code_offset) {
    591 }
    592 
    593 OatFile::OatMethod::~OatMethod() {}
    594 
    595 void OatFile::OatMethod::LinkMethod(mirror::ArtMethod* method) const {
    596   CHECK(method != NULL);
    597 #if defined(ART_USE_PORTABLE_COMPILER)
    598   method->SetEntryPointFromPortableCompiledCode(GetPortableCode());
    599 #endif
    600   method->SetEntryPointFromQuickCompiledCode(GetQuickCode());
    601 }
    602 
    603 bool OatFile::IsPic() const {
    604   return GetOatHeader().IsPic();
    605   // TODO: Check against oat_patches. b/18144996
    606 }
    607 
    608 }  // namespace art
    609