blob: 8af22b03c67c8df74a51e8d69ff6648a29aedd53 [file] [log] [blame]
// Copyright 2011 Google Inc. All Rights Reserved.
#include "oat_file.h"
#include <sys/mman.h>
#include "file.h"
#include "os.h"
#include "stl_util.h"
namespace art {
std::string OatFile::DexFilenameToOatFilename(const std::string& location) {
CHECK(IsValidDexFilename(location) || IsValidZipFilename(location));
std::string oat_location = location.substr(0, location.size()-3);
oat_location += "oat";
return oat_location;
}
OatFile* OatFile::Open(const std::string& filename,
const std::string& strip_location_prefix,
byte* requested_base) {
StringPiece location = filename;
if (!location.starts_with(strip_location_prefix)) {
LOG(ERROR) << filename << " does not start with " << strip_location_prefix;
return NULL;
}
location.remove_prefix(strip_location_prefix.size());
UniquePtr<OatFile> oat_file(new OatFile(location.ToString()));
bool success = oat_file->Read(filename, requested_base);
if (!success) {
return NULL;
}
return oat_file.release();
}
OatFile::OatFile(const std::string& filename) : location_(filename) {}
OatFile::~OatFile() {
STLDeleteValues(&oat_dex_files_);
}
bool OatFile::Read(const std::string& filename, byte* requested_base) {
UniquePtr<File> file(OS::OpenFile(filename.c_str(), false));
if (file.get() == NULL) {
return false;
}
OatHeader oat_header;
bool success = file->ReadFully(&oat_header, sizeof(oat_header));
if (!success || !oat_header.IsValid()) {
LOG(WARNING) << "Invalid oat header " << filename;
return false;
}
UniquePtr<MemMap> map(MemMap::Map(requested_base,
file->Length(),
PROT_READ,
MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0),
file->Fd(),
0));
if (map.get() == NULL) {
LOG(WARNING) << "Failed to map oat file " << filename;
return false;
}
CHECK(requested_base == 0 || requested_base == map->GetAddress()) << map->GetAddress();
DCHECK_EQ(0, memcmp(&oat_header, map->GetAddress(), sizeof(OatHeader)));
off_t code_offset = oat_header.GetExecutableOffset();
if (code_offset < file->Length()) {
byte* code_address = map->GetAddress() + code_offset;
size_t code_length = file->Length() - code_offset;
if (mprotect(code_address, code_length, PROT_READ | PROT_EXEC) != 0) {
PLOG(ERROR) << "Failed to make oat code executable.";
return false;
}
} else {
// its possible to have no code if all the methods were abstract, native, etc
DCHECK_EQ(code_offset, RoundUp(file->Length(), kPageSize));
}
const byte* oat = map->GetAddress();
oat += sizeof(OatHeader);
CHECK_LT(oat, map->GetLimit());
for (size_t i = 0; i < oat_header.GetDexFileCount(); i++) {
size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
oat += sizeof(dex_file_location_size);
CHECK_LT(oat, map->GetLimit());
const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
oat += dex_file_location_size;
CHECK_LT(oat, map->GetLimit());
std::string dex_file_location(dex_file_location_data, dex_file_location_size);
uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
oat += sizeof(dex_file_checksum);
CHECK_LT(oat, map->GetLimit());
uint32_t classes_offset = *reinterpret_cast<const uint32_t*>(oat);
CHECK_GT(classes_offset, 0U);
CHECK_LT(classes_offset, static_cast<uint32_t>(file->Length()));
oat += sizeof(classes_offset);
CHECK_LT(oat, map->GetLimit());
uint32_t* classes_pointer = reinterpret_cast<uint32_t*>(map->GetAddress() + classes_offset);
oat_dex_files_[dex_file_location] = new OatDexFile(this,
dex_file_location,
dex_file_checksum,
classes_pointer);
}
mem_map_.reset(map.release());
return true;
}
const OatHeader& OatFile::GetOatHeader() const {
return *reinterpret_cast<const OatHeader*>(GetBase());
}
const byte* OatFile::GetBase() const {
CHECK(mem_map_->GetAddress() != NULL);
return mem_map_->GetAddress();
}
const byte* OatFile::GetLimit() const {
CHECK(mem_map_->GetLimit() != NULL);
return mem_map_->GetLimit();
}
const OatFile::OatDexFile* OatFile::GetOatDexFile(const std::string& dex_file_location) const {
Table::const_iterator it = oat_dex_files_.find(dex_file_location);
if (it == oat_dex_files_.end()) {
LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_file_location;
return NULL;
}
return it->second;
}
std::vector<const OatFile::OatDexFile*> OatFile::GetOatDexFiles() const {
std::vector<const OatFile::OatDexFile*> result;
for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it) {
result.push_back(it->second);
}
return result;
}
OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
std::string dex_file_location,
uint32_t dex_file_checksum,
uint32_t* classes_pointer)
: oat_file_(oat_file),
dex_file_location_(dex_file_location),
dex_file_checksum_(dex_file_checksum),
classes_pointer_(classes_pointer) {}
OatFile::OatDexFile::~OatDexFile() {}
const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
uint32_t methods_offset = classes_pointer_[class_def_index];
const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
CHECK_LT(methods_pointer, oat_file_->GetLimit());
return new OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
}
OatFile::OatClass::OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer)
: oat_file_(oat_file), methods_pointer_(methods_pointer) {}
OatFile::OatClass::~OatClass() {}
const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
const OatMethodOffsets& oat_method_offsets = methods_pointer_[method_index];
return OatMethod(
GetOatPointer<const void*>(oat_method_offsets.code_offset_),
oat_method_offsets.frame_size_in_bytes_,
oat_method_offsets.return_pc_offset_in_bytes_,
oat_method_offsets.core_spill_mask_,
oat_method_offsets.fp_spill_mask_,
GetOatPointer<const uint32_t*>(oat_method_offsets.mapping_table_offset_),
GetOatPointer<const uint16_t*>(oat_method_offsets.vmap_table_offset_),
GetOatPointer<const Method::InvokeStub*>(oat_method_offsets.invoke_stub_offset_));
}
OatFile::OatMethod::OatMethod(const void* code,
const size_t frame_size_in_bytes,
const size_t return_pc_offset_in_bytes,
const uint32_t core_spill_mask,
const uint32_t fp_spill_mask,
const uint32_t* mapping_table,
const uint16_t* vmap_table,
const Method::InvokeStub* invoke_stub)
: code_(code),
frame_size_in_bytes_(frame_size_in_bytes),
return_pc_offset_in_bytes_(return_pc_offset_in_bytes),
core_spill_mask_(core_spill_mask),
fp_spill_mask_(fp_spill_mask),
mapping_table_(mapping_table),
vmap_table_(vmap_table),
invoke_stub_(invoke_stub) {
#ifndef NDEBUG
if (mapping_table != NULL) { // implies non-native, non-stub code
if (vmap_table_ == NULL) {
DCHECK_EQ(0U, static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + __builtin_popcount(fp_spill_mask_)));
} else {
DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + __builtin_popcount(fp_spill_mask_)));
}
} else {
DCHECK(vmap_table_ == NULL);
}
#endif
}
OatFile::OatMethod::~OatMethod() {}
void OatFile::OatMethod::LinkMethod(Method* method) const {
CHECK(method != NULL);
method->SetCode(code_);
method->SetFrameSizeInBytes(frame_size_in_bytes_);
method->SetCoreSpillMask(core_spill_mask_);
method->SetFpSpillMask(fp_spill_mask_);
method->SetMappingTable(mapping_table_);
method->SetVmapTable(vmap_table_);
method->SetInvokeStub(invoke_stub_);
}
} // namespace art