summaryrefslogtreecommitdiffstats
path: root/runtime/oat_file.h
blob: e9f7edca61968178eca71f204ba037ffa2652428 (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
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
/*
 * 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/array_ref.h"
#include "base/mutex.h"
#include "base/stringpiece.h"
#include "class_status.h"
#include "compiler_filter.h"
#include "dex/dex_file.h"
#include "dex/dex_file_layout.h"
#include "index_bss_mapping.h"
#include "mirror/object.h"
#include "oat.h"
#include "os.h"
#include "type_lookup_table.h"
#include "utf.h"
#include "utils.h"

namespace art {

class BitVector;
class ElfFile;
class DexLayoutSections;
template <class MirrorType> class GcRoot;
class MemMap;
class OatDexFile;
class OatHeader;
class OatMethodOffsets;
class OatQuickMethodHeader;
class VdexFile;

namespace gc {
namespace collector {
class DummyOatFile;
}  // namespace collector
}  // namespace gc

// Runtime representation of the OAT file format which holds compiler output.
// The class opens an OAT file from storage and maps it to memory, typically with
// dlopen and provides access to its internal data structures (see OatWriter for
// for more details about the OAT format).
// In the process of loading OAT, the class also loads the associated VDEX file
// with the input DEX files (see VdexFile for details about the VDEX format).
// The raw DEX data are accessible transparently through the OatDexFile objects.

class OatFile {
 public:
  // Special classpath that skips shared library check.
  static constexpr const char* kSpecialSharedLibrary = "&";

  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,
                                  VdexFile* vdex_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,
                       bool low_4gb,
                       const char* abs_dex_location,
                       std::string* error_msg);

  // Similar to OatFile::Open(const std::string...), but accepts input vdex and
  // odex files as file descriptors.
  static OatFile* Open(int vdex_fd,
                       int oat_fd,
                       const std::string& oat_location,
                       uint8_t* requested_base,
                       uint8_t* oat_file_begin,
                       bool executable,
                       bool low_4gb,
                       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);
  // Open 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);

  // Return the actual debug info offset for an offset that might be actually pointing to
  // dequickening info. The returned debug info offset is the one originally in the the dex file.
  static uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off);

  virtual ~OatFile();

  bool IsExecutable() const {
    return is_executable_;
  }

  bool IsPic() const;

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

  CompilerFilter::Filter GetCompilerFilter() const;

  std::string GetClassLoaderContext() const;

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

  const OatHeader& GetOatHeader() const;

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

    uint32_t GetCodeOffset() const;

    const void* GetQuickCode() const;

    // 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* GetVmapTable() const;
    uint32_t GetVmapTableOffset() const;
    uint32_t GetVmapTableOffsetOffset() 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:
    ClassStatus 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 FindOatClass().
    static OatClass Invalid() {
      return OatClass(/* oat_file */ nullptr,
                      ClassStatus::kErrorUnresolved,
                      kOatClassNoneCompiled,
                      /* bitmap_size */ 0,
                      /* bitmap_pointer */ nullptr,
                      /* methods_pointer */ nullptr);
    }

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

    const OatFile* const oat_file_;

    const ClassStatus status_;

    const OatClassType type_;

    const uint32_t* const bitmap_;

    const OatMethodOffsets* const methods_pointer_;

    friend class art::OatDexFile;
  };

  // Get the OatDexFile for the given dex_location within this oat file.
  // If dex_location_checksum is non-null, the OatDexFile will only be
  // returned if it has a matching checksum.
  // If error_msg is non-null and no OatDexFile is returned, error_msg will
  // be updated with a description of why no OatDexFile was returned.
  const OatDexFile* GetOatDexFile(const char* dex_location,
                                  const uint32_t* const dex_location_checksum,
                                  /*out*/std::string* error_msg = nullptr) const
      REQUIRES(!secondary_lookup_lock_);

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

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

  bool Contains(const void* p) const {
    return p >= Begin() && p < End();
  }

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

  size_t VdexSize() const {
    return VdexEnd() - VdexBegin();
  }

  size_t BssMethodsOffset() const {
    // Note: This is used only for symbolizer and needs to return a valid .bss offset.
    return (bss_methods_ != nullptr) ? bss_methods_ - BssBegin() : BssRootsOffset();
  }

  size_t BssRootsOffset() const {
    // Note: This is used only for symbolizer and needs to return a valid .bss offset.
    return (bss_roots_ != nullptr) ? bss_roots_ - BssBegin() : BssSize();
  }

  size_t DexSize() const {
    return DexEnd() - DexBegin();
  }

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

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

  const uint8_t* VdexBegin() const;
  const uint8_t* VdexEnd() const;

  const uint8_t* DexBegin() const;
  const uint8_t* DexEnd() const;

  ArrayRef<ArtMethod*> GetBssMethods() const;
  ArrayRef<GcRoot<mirror::Object>> GetBssGcRoots() 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);

  // Finds the associated oat class for a dex_file and descriptor. Returns an invalid OatClass on
  // error and sets found to false.
  static OatClass FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found);

  VdexFile* GetVdexFile() const {
    return vdex_.get();
  }

 protected:
  OatFile(const std::string& filename, bool executable);

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

  // Pointer to the Vdex file with the Dex files for this Oat file.
  std::unique_ptr<VdexFile> vdex_;

  // 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.
  uint8_t* bss_begin_;

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

  // Pointer to the beginning of the ArtMethod*s in .bss section, if present, otherwise null.
  uint8_t* bss_methods_;

  // Pointer to the beginning of the GC roots in .bss section, if present, otherwise null.
  uint8_t* bss_roots_;

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

  // Pointer to the .vdex section, if present, otherwise null.
  uint8_t* vdex_begin_;

  // Pointer to the end of the .vdex section, if present, otherwise null.
  uint8_t* vdex_end_;

  // 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 gc::collector::DummyOatFile;  // For modifying begin_ and end_.
  friend class OatClass;
  friend class art::OatDexFile;
  friend class OatDumper;  // For GetBase and GetLimit
  friend class OatFileBase;
  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;

  // May return null if the OatDexFile only contains a type lookup table. This case only happens
  // for the compiler to speed up compilation.
  const OatFile* GetOatFile() const {
    // Avoid pulling in runtime.h in the header file.
    if (kIsDebugBuild && oat_file_ == nullptr) {
      AssertAotCompiler();
    }
    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;

  const uint8_t* GetLookupTableData() const {
    return lookup_table_data_;
  }

  const IndexBssMapping* GetMethodBssMapping() const {
    return method_bss_mapping_;
  }

  const IndexBssMapping* GetTypeBssMapping() const {
    return type_bss_mapping_;
  }

  const IndexBssMapping* GetStringBssMapping() const {
    return string_bss_mapping_;
  }

  const uint8_t* GetDexFilePointer() const {
    return dex_file_pointer_;
  }

  // Looks up a class definition by its class descriptor. Hash must be
  // ComputeModifiedUtf8Hash(descriptor).
  static const DexFile::ClassDef* FindClassDef(const DexFile& dex_file,
                                               const char* descriptor,
                                               size_t hash);

  // Madvise the dex file based on the state we are moving to.
  static void MadviseDexFile(const DexFile& dex_file, MadviseState state);

  TypeLookupTable* GetTypeLookupTable() const {
    return lookup_table_.get();
  }

  ~OatDexFile();

  // Create only with a type lookup table, used by the compiler to speed up compilation.
  explicit OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table);

  // Return the dex layout sections.
  const DexLayoutSections* GetDexLayoutSections() const {
    return dex_layout_sections_;
  }

 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 uint8_t* lookup_table_data,
             const IndexBssMapping* method_bss_mapping,
             const IndexBssMapping* type_bss_mapping,
             const IndexBssMapping* string_bss_mapping,
             const uint32_t* oat_class_offsets_pointer,
             const DexLayoutSections* dex_layout_sections);

  static void AssertAotCompiler();

  const OatFile* const oat_file_ = nullptr;
  const std::string dex_file_location_;
  const std::string canonical_dex_file_location_;
  const uint32_t dex_file_location_checksum_ = 0u;
  const uint8_t* const dex_file_pointer_ = nullptr;
  const uint8_t* const lookup_table_data_ = nullptr;
  const IndexBssMapping* const method_bss_mapping_ = nullptr;
  const IndexBssMapping* const type_bss_mapping_ = nullptr;
  const IndexBssMapping* const string_bss_mapping_ = nullptr;
  const uint32_t* const oat_class_offsets_pointer_ = 0u;
  mutable std::unique_ptr<TypeLookupTable> lookup_table_;
  const DexLayoutSections* const dex_layout_sections_ = nullptr;

  friend class OatFile;
  friend class OatFileBase;
  DISALLOW_COPY_AND_ASSIGN(OatDexFile);
};

}  // namespace art

#endif  // ART_RUNTIME_OAT_FILE_H_