oat_file.cc revision ae826983f7903bc0a6bbbe8426bf393fb2f6d747
1// Copyright 2011 Google Inc. All Rights Reserved.
2
3#include "oat_file.h"
4
5#include <sys/mman.h>
6
7#include "file.h"
8#include "os.h"
9#include "stl_util.h"
10
11namespace art {
12
13std::string OatFile::DexFilenameToOatFilename(const std::string& location) {
14  CHECK(IsValidDexFilename(location) || IsValidZipFilename(location));
15  std::string oat_location = location.substr(0, location.size()-3);
16  oat_location += "oat";
17  return oat_location;
18}
19
20OatFile* OatFile::Open(const std::string& filename,
21                       const std::string& strip_location_prefix,
22                       byte* requested_base) {
23  StringPiece location = filename;
24  if (!location.starts_with(strip_location_prefix)) {
25    LOG(ERROR) << filename << " does not start with " << strip_location_prefix;
26    return NULL;
27  }
28  location.remove_prefix(strip_location_prefix.size());
29
30  UniquePtr<OatFile> oat_file(new OatFile(location.ToString()));
31  bool success = oat_file->Read(filename, requested_base);
32  if (!success) {
33    return NULL;
34  }
35  return oat_file.release();
36}
37
38OatFile::OatFile(const std::string& filename) : location_(filename) {}
39
40OatFile::~OatFile() {
41  STLDeleteValues(&oat_dex_files_);
42}
43
44bool OatFile::Read(const std::string& filename, byte* requested_base) {
45  UniquePtr<File> file(OS::OpenFile(filename.c_str(), false));
46  if (file.get() == NULL) {
47    return false;
48  }
49
50  OatHeader oat_header;
51  bool success = file->ReadFully(&oat_header, sizeof(oat_header));
52  if (!success || !oat_header.IsValid()) {
53    LOG(WARNING) << "Invalid oat header " << filename;
54    return false;
55  }
56
57  UniquePtr<MemMap> map(MemMap::Map(requested_base,
58                                    file->Length(),
59                                    PROT_READ,
60                                    MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0),
61                                    file->Fd(),
62                                    0));
63  if (map.get() == NULL) {
64    LOG(WARNING) << "Failed to map oat file " << filename;
65    return false;
66  }
67  CHECK(requested_base == 0 || requested_base == map->GetAddress()) << map->GetAddress();
68  DCHECK_EQ(0, memcmp(&oat_header, map->GetAddress(), sizeof(OatHeader)));
69
70  off_t code_offset = oat_header.GetExecutableOffset();
71  if (code_offset < file->Length()) {
72    byte* code_address = map->GetAddress() + code_offset;
73    size_t code_length = file->Length() - code_offset;
74    if (mprotect(code_address, code_length, PROT_READ | PROT_EXEC) != 0) {
75      PLOG(ERROR) << "Failed to make oat code executable.";
76      return false;
77    }
78  } else {
79    // its possible to have no code if all the methods were abstract, native, etc
80    DCHECK_EQ(code_offset, RoundUp(file->Length(), kPageSize));
81  }
82
83  const byte* oat = map->GetAddress();
84  oat += sizeof(OatHeader);
85  CHECK_LT(oat, map->GetLimit());
86  for (size_t i = 0; i < oat_header.GetDexFileCount(); i++) {
87    size_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
88    oat += sizeof(dex_file_location_size);
89    CHECK_LT(oat, map->GetLimit());
90
91    const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
92    oat += dex_file_location_size;
93    CHECK_LT(oat, map->GetLimit());
94
95    std::string dex_file_location(dex_file_location_data, dex_file_location_size);
96
97    uint32_t dex_file_checksum = *reinterpret_cast<const uint32_t*>(oat);
98    oat += sizeof(dex_file_checksum);
99    CHECK_LT(oat, map->GetLimit());
100
101    uint32_t classes_offset = *reinterpret_cast<const uint32_t*>(oat);
102    CHECK_GT(classes_offset, 0U);
103    CHECK_LT(classes_offset, static_cast<uint32_t>(file->Length()));
104    oat += sizeof(classes_offset);
105    CHECK_LT(oat, map->GetLimit());
106
107    uint32_t* classes_pointer = reinterpret_cast<uint32_t*>(map->GetAddress() + classes_offset);
108
109    oat_dex_files_[dex_file_location] = new OatDexFile(this,
110                                                       dex_file_location,
111                                                       dex_file_checksum,
112                                                       classes_pointer);
113  }
114
115  mem_map_.reset(map.release());
116  return true;
117}
118
119const OatHeader& OatFile::GetOatHeader() const {
120  return *reinterpret_cast<const OatHeader*>(GetBase());
121}
122
123const byte* OatFile::GetBase() const {
124  CHECK(mem_map_->GetAddress() != NULL);
125  return mem_map_->GetAddress();
126}
127
128const byte* OatFile::GetLimit() const {
129  CHECK(mem_map_->GetLimit() != NULL);
130  return mem_map_->GetLimit();
131}
132
133const OatFile::OatDexFile* OatFile::GetOatDexFile(const std::string& dex_file_location) const {
134  Table::const_iterator it = oat_dex_files_.find(dex_file_location);
135  if (it == oat_dex_files_.end()) {
136    LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_file_location;
137    return NULL;
138  }
139  return it->second;
140}
141
142std::vector<const OatFile::OatDexFile*> OatFile::GetOatDexFiles() const {
143  std::vector<const OatFile::OatDexFile*> result;
144  for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it) {
145    result.push_back(it->second);
146  }
147  return result;
148}
149
150OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
151                                std::string dex_file_location,
152                                uint32_t dex_file_checksum,
153                                uint32_t* classes_pointer)
154    : oat_file_(oat_file),
155      dex_file_location_(dex_file_location),
156      dex_file_checksum_(dex_file_checksum),
157      classes_pointer_(classes_pointer) {}
158
159OatFile::OatDexFile::~OatDexFile() {}
160
161const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
162  uint32_t methods_offset = classes_pointer_[class_def_index];
163  const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
164  CHECK_LT(methods_pointer, oat_file_->GetLimit());
165  return new OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
166}
167
168OatFile::OatClass::OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer)
169    : oat_file_(oat_file), methods_pointer_(methods_pointer) {}
170
171OatFile::OatClass::~OatClass() {}
172
173const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
174  const OatMethodOffsets& oat_method_offsets = methods_pointer_[method_index];
175  return OatMethod(
176      oat_file_->GetBase(),
177      oat_method_offsets.code_offset_,
178      oat_method_offsets.frame_size_in_bytes_,
179      oat_method_offsets.core_spill_mask_,
180      oat_method_offsets.fp_spill_mask_,
181      oat_method_offsets.mapping_table_offset_,
182      oat_method_offsets.vmap_table_offset_,
183      oat_method_offsets.invoke_stub_offset_);
184}
185
186OatFile::OatMethod::OatMethod(const byte* base,
187                              const uint32_t code_offset,
188                              const size_t frame_size_in_bytes,
189                              const uint32_t core_spill_mask,
190                              const uint32_t fp_spill_mask,
191                              const uint32_t mapping_table_offset,
192                              const uint32_t vmap_table_offset,
193                              const uint32_t invoke_stub_offset)
194  : base_(base),
195    code_offset_(code_offset),
196    frame_size_in_bytes_(frame_size_in_bytes),
197    core_spill_mask_(core_spill_mask),
198    fp_spill_mask_(fp_spill_mask),
199    mapping_table_offset_(mapping_table_offset),
200    vmap_table_offset_(vmap_table_offset),
201    invoke_stub_offset_(invoke_stub_offset) {
202
203#ifndef NDEBUG
204  if (mapping_table_offset_ != 0) {  // implies non-native, non-stub code
205    if (vmap_table_offset_ == 0) {
206      DCHECK_EQ(0U, static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + __builtin_popcount(fp_spill_mask_)));
207    } else {
208      const uint16_t* vmap_table_ = reinterpret_cast<const uint16_t*>(base_ + vmap_table_offset_);
209      DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + __builtin_popcount(fp_spill_mask_)));
210    }
211  } else {
212    DCHECK(vmap_table_offset_ == 0);
213  }
214#endif
215}
216
217OatFile::OatMethod::~OatMethod() {}
218
219void OatFile::OatMethod::LinkMethodPointers(Method* method) const {
220  CHECK(method != NULL);
221  method->SetCode(GetCode());
222  method->SetFrameSizeInBytes(frame_size_in_bytes_);
223  method->SetCoreSpillMask(core_spill_mask_);
224  method->SetFpSpillMask(fp_spill_mask_);
225  method->SetMappingTable(GetMappingTable());
226  method->SetVmapTable(GetVmapTable());
227  method->SetInvokeStub(GetInvokeStub());
228}
229
230void OatFile::OatMethod::LinkMethodOffsets(Method* method) const {
231  CHECK(method != NULL);
232  method->SetOatCodeOffset(GetCodeOffset());
233  method->SetFrameSizeInBytes(GetFrameSizeInBytes());
234  method->SetCoreSpillMask(GetCoreSpillMask());
235  method->SetFpSpillMask(GetFpSpillMask());
236  method->SetOatMappingTableOffset(GetMappingTableOffset());
237  method->SetOatVmapTableOffset(GetVmapTableOffset());
238  method->SetOatInvokeStubOffset(GetInvokeStubOffset());
239}
240
241}  // namespace art
242