summaryrefslogtreecommitdiffstats
path: root/runtime/oat_file.h
blob: 1a782deb828bdc336280c1176a9b827658a94824 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_RUNTIME_OAT_FILE_H_
#define ART_RUNTIME_OAT_FILE_H_

#include <list>
#include <string>
#include <vector>

#include "base/mutex.h"
#include "base/stringpiece.h"
#include "dex_file.h"
#include "invoke_type.h"
#include "mem_map.h"
#include "mirror/class.h"
#include "oat.h"
#include "os.h"

namespace art {

class BitVector;
class ElfFile;
class MemMap;
class OatMethodOffsets;
class OatHeader;
class OatDexFile;

class OatFile FINAL {
 public:
  typedef art::OatDexFile OatDexFile;

  // Opens an oat file contained within the given elf file. This is always opened as
  // non-executable at the moment.
  static OatFile* OpenWithElfFile(ElfFile* elf_file, const std::string& location,
                                  const char* abs_dex_location,
                                  std::string* error_msg);
  // Open an oat file. Returns null on failure.  Requested base can
  // optionally be used to request where the file should be loaded.
  // See the ResolveRelativeEncodedDexLocation for a description of how the
  // abs_dex_location argument is used.
  static OatFile* Open(const std::string& filename,
                       const std::string& location,
                       uint8_t* requested_base,
                       uint8_t* oat_file_begin,
                       bool executable,
                       const char* abs_dex_location,
                       std::string* error_msg);

  // Open an oat file from an already opened File.
  // Does not use dlopen underneath so cannot be used for runtime use
  // where relocations may be required. Currently used from
  // ImageWriter which wants to open a writable version from an existing
  // file descriptor for patching.
  static OatFile* OpenWritable(File* file, const std::string& location,
                               const char* abs_dex_location,
                               std::string* error_msg);
  // Opens an oat file from an already opened File. Maps it PROT_READ, MAP_PRIVATE.
  static OatFile* OpenReadable(File* file, const std::string& location,
                               const char* abs_dex_location,
                               std::string* error_msg);

  ~OatFile();

  bool IsExecutable() const {
    return is_executable_;
  }

  bool IsPic() const;

  // Indicates whether the oat file was compiled with full debugging capability.
  bool IsDebuggable() const;

  ElfFile* GetElfFile() const {
    CHECK_NE(reinterpret_cast<uintptr_t>(elf_file_.get()), reinterpret_cast<uintptr_t>(nullptr))
        << "Cannot get an elf file from " << GetLocation();
    return elf_file_.get();
  }

  const std::string& GetLocation() const {
    return location_;
  }

  const OatHeader& GetOatHeader() const;

  class OatMethod FINAL {
   public:
    void LinkMethod(ArtMethod* method) const;

    uint32_t GetCodeOffset() const {
      return code_offset_;
    }

    const void* GetQuickCode() const {
      return GetOatPointer<const void*>(code_offset_);
    }

    // Returns size of quick code.
    uint32_t GetQuickCodeSize() const;
    uint32_t GetQuickCodeSizeOffset() const;

    // Returns OatQuickMethodHeader for debugging. Most callers should
    // use more specific methods such as GetQuickCodeSize.
    const OatQuickMethodHeader* GetOatQuickMethodHeader() const;
    uint32_t GetOatQuickMethodHeaderOffset() const;

    size_t GetFrameSizeInBytes() const;
    uint32_t GetCoreSpillMask() const;
    uint32_t GetFpSpillMask() const;

    const uint8_t* GetMappingTable() const;
    uint32_t GetMappingTableOffset() const;
    uint32_t GetMappingTableOffsetOffset() const;

    const uint8_t* GetVmapTable() const;
    uint32_t GetVmapTableOffset() const;
    uint32_t GetVmapTableOffsetOffset() const;

    const uint8_t* GetGcMap() const;
    uint32_t GetGcMapOffset() const;
    uint32_t GetGcMapOffsetOffset() const;

    // Create an OatMethod with offsets relative to the given base address
    OatMethod(const uint8_t* base, const uint32_t code_offset)
        : begin_(base), code_offset_(code_offset) {
    }
    OatMethod(const OatMethod&) = default;
    ~OatMethod() {}

    OatMethod& operator=(const OatMethod&) = default;

    // A representation of an invalid OatMethod, used when an OatMethod or OatClass can't be found.
    // See ClassLinker::FindOatMethodFor.
    static const OatMethod Invalid() {
      return OatMethod(nullptr, -1);
    }

   private:
    template<class T>
    T GetOatPointer(uint32_t offset) const {
      if (offset == 0) {
        return nullptr;
      }
      return reinterpret_cast<T>(begin_ + offset);
    }

    const uint8_t* begin_;
    uint32_t code_offset_;

    friend class OatClass;
  };

  class OatClass FINAL {
   public:
    mirror::Class::Status GetStatus() const {
      return status_;
    }

    OatClassType GetType() const {
      return type_;
    }

    // Get the OatMethod entry based on its index into the class
    // defintion. Direct methods come first, followed by virtual
    // methods. Note that runtime created methods such as miranda
    // methods are not included.
    const OatMethod GetOatMethod(uint32_t method_index) const;

    // Return a pointer to the OatMethodOffsets for the requested
    // method_index, or null if none is present. Note that most
    // callers should use GetOatMethod.
    const OatMethodOffsets* GetOatMethodOffsets(uint32_t method_index) const;

    // Return the offset from the start of the OatFile to the
    // OatMethodOffsets for the requested method_index, or 0 if none
    // is present. Note that most callers should use GetOatMethod.
    uint32_t GetOatMethodOffsetsOffset(uint32_t method_index) const;

    // A representation of an invalid OatClass, used when an OatClass can't be found.
    // See ClassLinker::FindOatClass.
    static OatClass Invalid() {
      return OatClass(nullptr, mirror::Class::kStatusError, kOatClassNoneCompiled, 0, nullptr,
                      nullptr);
    }

   private:
    OatClass(const OatFile* oat_file,
             mirror::Class::Status status,
             OatClassType type,
             uint32_t bitmap_size,
             const uint32_t* bitmap_pointer,
             const OatMethodOffsets* methods_pointer);

    const OatFile* const oat_file_;

    const mirror::Class::Status status_;

    const OatClassType type_;

    const uint32_t* const bitmap_;

    const OatMethodOffsets* const methods_pointer_;

    friend class art::OatDexFile;
  };
  const OatDexFile* GetOatDexFile(const char* dex_location,
                                  const uint32_t* const dex_location_checksum,
                                  bool exception_if_not_found = true) const
      LOCKS_EXCLUDED(secondary_lookup_lock_);

  const std::vector<const OatDexFile*>& GetOatDexFiles() const {
    return oat_dex_files_storage_;
  }

  size_t Size() const {
    return End() - Begin();
  }

  size_t BssSize() const {
    return BssEnd() - BssBegin();
  }

  const uint8_t* Begin() const;
  const uint8_t* End() const;

  const uint8_t* BssBegin() const;
  const uint8_t* BssEnd() const;

  // Returns the absolute dex location for the encoded relative dex location.
  //
  // If not null, abs_dex_location is used to resolve the absolute dex
  // location of relative dex locations encoded in the oat file.
  // For example, given absolute location "/data/app/foo/base.apk", encoded
  // dex locations "base.apk", "base.apk:classes2.dex", etc. would be resolved
  // to "/data/app/foo/base.apk", "/data/app/foo/base.apk:classes2.dex", etc.
  // Relative encoded dex locations that don't match the given abs_dex_location
  // are left unchanged.
  static std::string ResolveRelativeEncodedDexLocation(
      const char* abs_dex_location, const std::string& rel_dex_location);

  // Create a dependency list (dex locations and checksums) for the given dex files.
  static std::string EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files);

  // Check the given dependency list against their dex files - thus the name "Static," this does
  // not check the class-loader environment, only whether there have been file updates.
  static bool CheckStaticDexFileDependencies(const char* dex_dependencies, std::string* msg);

  // Get the dex locations of a dependency list. Note: this is *not* cleaned for synthetic
  // locations of multidex files.
  static bool GetDexLocationsFromDependencies(const char* dex_dependencies,
                                              std::vector<std::string>* locations);

 private:
  static void CheckLocation(const std::string& location);

  static OatFile* OpenDlopen(const std::string& elf_filename,
                             const std::string& location,
                             uint8_t* requested_base,
                             const char* abs_dex_location,
                             std::string* error_msg);

  static OatFile* OpenElfFile(File* file,
                              const std::string& location,
                              uint8_t* requested_base,
                              uint8_t* oat_file_begin,  // Override base if not null
                              bool writable,
                              bool executable,
                              const char* abs_dex_location,
                              std::string* error_msg);

  explicit OatFile(const std::string& filename, bool executable);
  bool Dlopen(const std::string& elf_filename, uint8_t* requested_base,
              const char* abs_dex_location, std::string* error_msg);
  bool ElfFileOpen(File* file, uint8_t* requested_base,
                   uint8_t* oat_file_begin,  // Override where the file is loaded to if not null
                   bool writable, bool executable,
                   const char* abs_dex_location,
                   std::string* error_msg);

  bool Setup(const char* abs_dex_location, std::string* error_msg);

  // The oat file name.
  //
  // The image will embed this to link its associated oat file.
  const std::string location_;

  // Pointer to OatHeader.
  const uint8_t* begin_;

  // Pointer to end of oat region for bounds checking.
  const uint8_t* end_;

  // Pointer to the .bss section, if present, otherwise null.
  const uint8_t* bss_begin_;

  // Pointer to the end of the .bss section, if present, otherwise null.
  const uint8_t* bss_end_;

  // Was this oat_file loaded executable?
  const bool is_executable_;

  // Backing memory map for oat file during when opened by ElfWriter during initial compilation.
  std::unique_ptr<MemMap> mem_map_;

  // Backing memory map for oat file during cross compilation.
  std::unique_ptr<ElfFile> elf_file_;

  // dlopen handle during runtime.
  void* dlopen_handle_;

  // Dummy memory map objects corresponding to the regions mapped by dlopen.
  std::vector<std::unique_ptr<MemMap>> dlopen_mmaps_;

  // Owning storage for the OatDexFile objects.
  std::vector<const OatDexFile*> oat_dex_files_storage_;

  // NOTE: We use a StringPiece as the key type to avoid a memory allocation on every
  // lookup with a const char* key. The StringPiece doesn't own its backing storage,
  // therefore we're using the OatDexFile::dex_file_location_ as the backing storage
  // for keys in oat_dex_files_ and the string_cache_ entries for the backing storage
  // of keys in secondary_oat_dex_files_ and oat_dex_files_by_canonical_location_.
  typedef AllocationTrackingSafeMap<StringPiece, const OatDexFile*, kAllocatorTagOatFile> Table;

  // Map each location and canonical location (if different) retrieved from the
  // oat file to its OatDexFile. This map doesn't change after it's constructed in Setup()
  // and therefore doesn't need any locking and provides the cheapest dex file lookup
  // for GetOatDexFile() for a very frequent use case. Never contains a null value.
  Table oat_dex_files_;

  // Lock guarding all members needed for secondary lookup in GetOatDexFile().
  mutable Mutex secondary_lookup_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;

  // If the primary oat_dex_files_ lookup fails, use a secondary map. This map stores
  // the results of all previous secondary lookups, whether successful (non-null) or
  // failed (null). If it doesn't contain an entry we need to calculate the canonical
  // location and use oat_dex_files_by_canonical_location_.
  mutable Table secondary_oat_dex_files_ GUARDED_BY(secondary_lookup_lock_);

  // Cache of strings. Contains the backing storage for keys in the secondary_oat_dex_files_
  // and the lazily initialized oat_dex_files_by_canonical_location_.
  // NOTE: We're keeping references to contained strings in form of StringPiece and adding
  // new strings to the end. The adding of a new element must not touch any previously stored
  // elements. std::list<> and std::deque<> satisfy this requirement, std::vector<> doesn't.
  mutable std::list<std::string> string_cache_ GUARDED_BY(secondary_lookup_lock_);

  friend class OatClass;
  friend class art::OatDexFile;
  friend class OatDumper;  // For GetBase and GetLimit
  DISALLOW_COPY_AND_ASSIGN(OatFile);
};

// OatDexFile should be an inner class of OatFile. Unfortunately, C++ doesn't
// support forward declarations of inner classes, and we want to
// forward-declare OatDexFile so that we can store an opaque pointer to an
// OatDexFile in DexFile.
class OatDexFile FINAL {
 public:
  // Opens the DexFile referred to by this OatDexFile from within the containing OatFile.
  std::unique_ptr<const DexFile> OpenDexFile(std::string* error_msg) const;

  const OatFile* GetOatFile() const {
    return oat_file_;
  }

  // Returns the size of the DexFile refered to by this OatDexFile.
  size_t FileSize() const;

  // Returns original path of DexFile that was the source of this OatDexFile.
  const std::string& GetDexFileLocation() const {
    return dex_file_location_;
  }

  // Returns the canonical location of DexFile that was the source of this OatDexFile.
  const std::string& GetCanonicalDexFileLocation() const {
    return canonical_dex_file_location_;
  }

  // Returns checksum of original DexFile that was the source of this OatDexFile;
  uint32_t GetDexFileLocationChecksum() const {
    return dex_file_location_checksum_;
  }

  // Returns the OatClass for the class specified by the given DexFile class_def_index.
  OatFile::OatClass GetOatClass(uint16_t class_def_index) const;

  // Returns the offset to the OatClass information. Most callers should use GetOatClass.
  uint32_t GetOatClassOffset(uint16_t class_def_index) const;

  ~OatDexFile();

 private:
  OatDexFile(const OatFile* oat_file,
             const std::string& dex_file_location,
             const std::string& canonical_dex_file_location,
             uint32_t dex_file_checksum,
             const uint8_t* dex_file_pointer,
             const uint32_t* oat_class_offsets_pointer);

  const OatFile* const oat_file_;
  const std::string dex_file_location_;
  const std::string canonical_dex_file_location_;
  const uint32_t dex_file_location_checksum_;
  const uint8_t* const dex_file_pointer_;
  const uint32_t* const oat_class_offsets_pointer_;

  friend class OatFile;
  DISALLOW_COPY_AND_ASSIGN(OatDexFile);
};

}  // namespace art

#endif  // ART_RUNTIME_OAT_FILE_H_