blob: 4ad701f96beeebe86821022938378e33e66a6619 [file] [log] [blame]
// Copyright 2011 Google Inc. All Rights Reserved.
#ifndef ART_SRC_DEX_FILE_H_
#define ART_SRC_DEX_FILE_H_
#include <map>
#include <string>
#include <vector>
#include "UniquePtr.h"
#include "globals.h"
#include "jni.h"
#include "leb128.h"
#include "logging.h"
#include "mutex.h"
#include "stringpiece.h"
#include "strutil.h"
#include "utils.h"
namespace art {
union JValue;
class String;
class Method;
// TODO: move all of the macro functionality into the DexCache class.
class DexFile {
public:
static const byte kDexMagic[];
static const byte kDexMagicVersion[];
static const size_t kSha1DigestSize = 20;
static const byte kEncodedValueTypeMask = 0x1f; // 0b11111
static const byte kEncodedValueArgShift = 5;
// The value of an invalid index.
static const uint32_t kDexNoIndex = 0xFFFFFFFF;
enum ValueType {
kByte = 0x00,
kShort = 0x02,
kChar = 0x03,
kInt = 0x04,
kLong = 0x06,
kFloat = 0x10,
kDouble = 0x11,
kString = 0x17,
kType = 0x18,
kField = 0x19,
kMethod = 0x1a,
kEnum = 0x1b,
kArray = 0x1c,
kAnnotation = 0x1d,
kNull = 0x1e,
kBoolean = 0x1f
};
// Raw header_item.
struct Header {
uint8_t magic_[8];
uint32_t checksum_;
uint8_t signature_[kSha1DigestSize];
uint32_t file_size_; // length of entire file
uint32_t header_size_; // offset to start of next section
uint32_t endian_tag_;
uint32_t link_size_;
uint32_t link_off_;
uint32_t map_off_;
uint32_t string_ids_size_;
uint32_t string_ids_off_;
uint32_t type_ids_size_;
uint32_t type_ids_off_;
uint32_t proto_ids_size_;
uint32_t proto_ids_off_;
uint32_t field_ids_size_;
uint32_t field_ids_off_;
uint32_t method_ids_size_;
uint32_t method_ids_off_;
uint32_t class_defs_size_;
uint32_t class_defs_off_;
uint32_t data_size_;
uint32_t data_off_;
private:
DISALLOW_COPY_AND_ASSIGN(Header);
};
// Raw string_id_item.
struct StringId {
uint32_t string_data_off_; // offset in bytes from the base address
private:
DISALLOW_COPY_AND_ASSIGN(StringId);
};
// Raw type_id_item.
struct TypeId {
uint32_t descriptor_idx_; // index into string_ids
private:
DISALLOW_COPY_AND_ASSIGN(TypeId);
};
// Raw field_id_item.
struct FieldId {
uint16_t class_idx_; // index into type_ids_ list for defining class
uint16_t type_idx_; // index into type_ids_ for field type
uint32_t name_idx_; // index into string_ids_ for field name
private:
DISALLOW_COPY_AND_ASSIGN(FieldId);
};
// Raw method_id_item.
struct MethodId {
uint16_t class_idx_; // index into type_ids_ list for defining class
uint16_t proto_idx_; // index into proto_ids_ for method prototype
uint32_t name_idx_; // index into string_ids_ for method name
private:
DISALLOW_COPY_AND_ASSIGN(MethodId);
};
// Raw proto_id_item.
struct ProtoId {
uint32_t shorty_idx_; // index into string_ids for shorty descriptor
uint32_t return_type_idx_; // index into type_ids list for return type
uint32_t parameters_off_; // file offset to type_list for parameter types
private:
DISALLOW_COPY_AND_ASSIGN(ProtoId);
};
// Raw class_def_item.
struct ClassDef {
uint32_t class_idx_; // index into type_ids_ for this class
uint32_t access_flags_;
uint32_t superclass_idx_; // index into type_ids_ for superclass
uint32_t interfaces_off_; // file offset to TypeList
uint32_t source_file_idx_; // index into string_ids_ for source file name
uint32_t annotations_off_; // file offset to annotations_directory_item
uint32_t class_data_off_; // file offset to class_data_item
uint32_t static_values_off_; // file offset to EncodedArray
private:
DISALLOW_COPY_AND_ASSIGN(ClassDef);
};
// Raw type_item.
struct TypeItem {
uint16_t type_idx_; // index into type_ids section
private:
DISALLOW_COPY_AND_ASSIGN(TypeItem);
};
// Raw type_list.
class TypeList {
public:
uint32_t Size() const {
return size_;
}
const TypeItem& GetTypeItem(uint32_t idx) const {
CHECK_LT(idx, this->size_);
return this->list_[idx];
}
private:
uint32_t size_; // size of the list, in entries
TypeItem list_[1]; // elements of the list
DISALLOW_COPY_AND_ASSIGN(TypeList);
};
class ParameterIterator { // TODO: stream
public:
ParameterIterator(const DexFile& dex_file, const ProtoId& proto_id)
: dex_file_(dex_file), size_(0), pos_(0) {
type_list_ = dex_file_.GetProtoParameters(proto_id);
if (type_list_ != NULL) {
size_ = type_list_->Size();
}
}
bool HasNext() const { return pos_ != size_; }
void Next() { ++pos_; }
const char* GetDescriptor() {
uint32_t type_idx = type_list_->GetTypeItem(pos_).type_idx_;
return dex_file_.dexStringByTypeIdx(type_idx);
}
private:
const DexFile& dex_file_;
const TypeList* type_list_;
uint32_t size_;
uint32_t pos_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterIterator);
};
ParameterIterator* GetParameterIterator(const ProtoId& proto_id) const {
return new ParameterIterator(*this, proto_id);
}
const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const {
return dexStringByTypeIdx(proto_id.return_type_idx_);
}
// Raw code_item.
struct CodeItem {
uint16_t registers_size_;
uint16_t ins_size_;
uint16_t outs_size_;
uint16_t tries_size_;
uint32_t debug_info_off_; // file offset to debug info stream
uint32_t insns_size_; // size of the insns array, in 2 byte code units
uint16_t insns_[1];
private:
DISALLOW_COPY_AND_ASSIGN(CodeItem);
};
struct CatchHandlerItem {
uint32_t type_idx_; // type index of the caught exception type
uint32_t address_; // handler address
};
// Raw try_item.
struct TryItem {
uint32_t start_addr_;
uint16_t insn_count_;
uint16_t handler_off_;
private:
DISALLOW_COPY_AND_ASSIGN(TryItem);
};
class CatchHandlerIterator {
public:
CatchHandlerIterator() {
remaining_count_ = -1;
catch_all_ = false;
}
CatchHandlerIterator(const byte* handler_data) {
current_data_ = handler_data;
remaining_count_ = DecodeSignedLeb128(&current_data_);
// If remaining_count_ is non-positive, then it is the negative of
// the number of catch types, and the catches are followed by a
// catch-all handler.
if (remaining_count_ <= 0) {
catch_all_ = true;
remaining_count_ = -remaining_count_;
} else {
catch_all_ = false;
}
Next();
}
const CatchHandlerItem& Get() const {
return handler_;
}
const byte* GetData() const {
return current_data_;
}
void Next() {
if (remaining_count_ > 0) {
handler_.type_idx_ = DecodeUnsignedLeb128(&current_data_);
handler_.address_ = DecodeUnsignedLeb128(&current_data_);
remaining_count_--;
return;
}
if (catch_all_) {
handler_.type_idx_ = kDexNoIndex;
handler_.address_ = DecodeUnsignedLeb128(&current_data_);
catch_all_ = false;
return;
}
// no more handler
remaining_count_ = -1;
}
bool HasNext() const {
return remaining_count_ == -1 && catch_all_ == false;
}
private:
CatchHandlerItem handler_;
const byte *current_data_; // the current handler in dex file.
int32_t remaining_count_; // number of handlers not read.
bool catch_all_; // is there a handler that will catch all exceptions in case
// that all typed handler does not match.
};
// Partially decoded form of class_data_item.
struct ClassDataHeader {
uint32_t static_fields_size_; // the number of static fields
uint32_t instance_fields_size_; // the number of instance fields
uint32_t direct_methods_size_; // the number of direct methods
uint32_t virtual_methods_size_; // the number of virtual methods
};
// Decoded form of encoded_field.
struct Field {
uint32_t field_idx_; // index into the field_ids list for the identity of this field
uint32_t access_flags_; // access flags for the field
Field() {};
private:
DISALLOW_COPY_AND_ASSIGN(Field);
};
// Decoded form of encoded_method.
struct Method {
uint32_t method_idx_;
uint32_t access_flags_;
uint32_t code_off_;
Method() {};
private:
DISALLOW_COPY_AND_ASSIGN(Method);
};
typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry;
typedef std::vector<const DexFile*> ClassPath;
// Search a collection of DexFiles for a descriptor
static ClassPathEntry FindInClassPath(const StringPiece& descriptor,
const ClassPath& class_path);
// Opens a collection of .dex files
static void OpenDexFiles(std::vector<const char*>& dex_filenames,
std::vector<const DexFile*>& dex_files,
const std::string& strip_location_prefix);
// Opens .dex file, guessing the format based on file extension
static const DexFile* Open(const std::string& filename,
const std::string& strip_location_prefix);
// Opens a .dex file from the file system.
static const DexFile* OpenFile(const std::string& filename,
const std::string& original_location,
const std::string& strip_location_prefix);
// Opens a .jar, .zip, or .apk file from the file system.
static const DexFile* OpenZip(const std::string& filename,
const std::string& strip_location_prefix);
// Opens a .dex file from a new allocated pointer. location is used
// to identify the source, for example "/system/framework/core.jar"
// or "contrived-test-42". When initializing a ClassLinker from an
// image, the location is used to match DexCaches the image to their
// corresponding DexFiles.N
static const DexFile* OpenPtr(byte* ptr, size_t length, const std::string& location);
// Closes a .dex file.
virtual ~DexFile();
const std::string& GetLocation() const {
return location_;
}
// Returns a com.android.dex.Dex object corresponding to the mapped-in dex file.
// Used by managed code to implement annotations.
jobject GetDexObject(JNIEnv* env) const;
const Header& GetHeader() const {
CHECK(header_ != NULL);
return *header_;
}
// Looks up a class definition by its class descriptor.
const ClassDef* FindClassDef(const StringPiece& descriptor) const;
// Returns the number of string identifiers in the .dex file.
size_t NumStringIds() const {
CHECK(header_ != NULL);
return header_->string_ids_size_;
}
// Returns the number of type identifiers in the .dex file.
size_t NumTypeIds() const {
CHECK(header_ != NULL);
return header_->type_ids_size_;
}
// Returns the number of prototype identifiers in the .dex file.
size_t NumProtoIds() const {
CHECK(header_ != NULL);
return header_->proto_ids_size_;
}
// Returns the number of field identifiers in the .dex file.
size_t NumFieldIds() const {
CHECK(header_ != NULL);
return header_->field_ids_size_;
}
// Returns the number of method identifiers in the .dex file.
size_t NumMethodIds() const {
CHECK(header_ != NULL);
return header_->method_ids_size_;
}
// Returns the number of class definitions in the .dex file.
size_t NumClassDefs() const {
CHECK(header_ != NULL);
return header_->class_defs_size_;
}
// Returns a pointer to the memory mapped class data.
// TODO: return a stream
const byte* GetClassData(const ClassDef& class_def) const {
if (class_def.class_data_off_ == 0) {
return NULL;
} else {
return base_ + class_def.class_data_off_;
}
}
// Decodes the header section from the class data bytes.
ClassDataHeader ReadClassDataHeader(const byte** class_data) const {
CHECK(class_data != NULL);
ClassDataHeader header;
memset(&header, 0, sizeof(ClassDataHeader));
if (*class_data != NULL) {
header.static_fields_size_ = DecodeUnsignedLeb128(class_data);
header.instance_fields_size_ = DecodeUnsignedLeb128(class_data);
header.direct_methods_size_ = DecodeUnsignedLeb128(class_data);
header.virtual_methods_size_ = DecodeUnsignedLeb128(class_data);
}
return header;
}
// Returns the class descriptor string of a class definition.
const char* GetClassDescriptor(const ClassDef& class_def) const {
return dexStringByTypeIdx(class_def.class_idx_);
}
// Returns the type descriptor string of a type id.
const char* GetTypeDescriptor(const TypeId& type_id) const {
return dexStringById(type_id.descriptor_idx_);
}
// Returns the class descriptor string of a field id.
const char* GetFieldClassDescriptor(const FieldId& field_id) const {
const DexFile::TypeId& type_id = GetTypeId(field_id.class_idx_);
return GetTypeDescriptor(type_id);
}
// Returns the name of a field id.
const char* GetFieldName(const FieldId& field_id) const {
return dexStringById(field_id.name_idx_);
}
// Returns the class descriptor string of a method id.
const char* GetMethodClassDescriptor(const MethodId& method_id) const {
const DexFile::TypeId& type_id = GetTypeId(method_id.class_idx_);
return GetTypeDescriptor(type_id);
}
// Returns the prototype of a method id.
const char* GetMethodPrototype(const MethodId& method_id) const {
return dexStringById(method_id.proto_idx_);
}
// Returns the name of a method id.
const char* GetMethodName(const MethodId& method_id) const {
return dexStringById(method_id.name_idx_);
}
// Returns the StringId at the specified index.
const StringId& GetStringId(uint32_t idx) const {
CHECK_LT(idx, NumStringIds());
return string_ids_[idx];
}
// Returns the TypeId at the specified index.
const TypeId& GetTypeId(uint32_t idx) const {
CHECK_LT(idx, NumTypeIds());
return type_ids_[idx];
}
// Returns the FieldId at the specified index.
const FieldId& GetFieldId(uint32_t idx) const {
CHECK_LT(idx, NumFieldIds());
return field_ids_[idx];
}
// Returns the MethodId at the specified index.
const MethodId& GetMethodId(uint32_t idx) const {
CHECK_LT(idx, NumMethodIds());
return method_ids_[idx];
}
// Returns the ProtoId at the specified index.
const ProtoId& GetProtoId(uint32_t idx) const {
CHECK_LT(idx, NumProtoIds());
return proto_ids_[idx];
}
// Returns the ClassDef at the specified index.
const ClassDef& GetClassDef(uint32_t idx) const {
CHECK_LT(idx, NumClassDefs());
return class_defs_[idx];
}
const TypeList* GetInterfacesList(const ClassDef& class_def) const {
if (class_def.interfaces_off_ == 0) {
return NULL;
} else {
const byte* addr = base_ + class_def.interfaces_off_;
return reinterpret_cast<const TypeList*>(addr);
}
}
const CodeItem* GetCodeItem(const Method& method) const {
return GetCodeItem(method.code_off_);
}
const CodeItem* GetCodeItem(const uint32_t code_off_) const {
if (code_off_ == 0) {
return NULL; // native or abstract method
} else {
const byte* addr = base_ + code_off_;
return reinterpret_cast<const CodeItem*>(addr);
}
}
// Returns the short form method descriptor for the given prototype.
const char* GetShorty(uint32_t proto_idx) const {
const ProtoId& proto_id = GetProtoId(proto_idx);
return dexStringById(proto_id.shorty_idx_);
}
const TypeList* GetProtoParameters(const ProtoId& proto_id) const {
if (proto_id.parameters_off_ == 0) {
return NULL;
} else {
const byte* addr = base_ + proto_id.parameters_off_;
return reinterpret_cast<const TypeList*>(addr);
}
}
std::string CreateMethodDescriptor(uint32_t proto_idx, int32_t* unicode_length) const;
const byte* GetEncodedArray(const ClassDef& class_def) const {
if (class_def.static_values_off_ == 0) {
return 0;
} else {
return base_ + class_def.static_values_off_;
}
}
int32_t GetStringLength(const StringId& string_id) const {
const byte* ptr = base_ + string_id.string_data_off_;
return DecodeUnsignedLeb128(&ptr);
}
ValueType ReadEncodedValue(const byte** encoded_value, JValue* value) const;
// From libdex...
// Returns a pointer to the UTF-8 string data referred to by the
// given string_id.
const char* GetStringData(const StringId& string_id, int32_t* length) const {
CHECK(length != NULL);
const byte* ptr = base_ + string_id.string_data_off_;
*length = DecodeUnsignedLeb128(&ptr);
return reinterpret_cast<const char*>(ptr);
}
const char* GetStringData(const StringId& string_id) const {
int32_t length;
return GetStringData(string_id, &length);
}
// return the UTF-8 encoded string with the specified string_id index
const char* dexStringById(uint32_t idx, int32_t* unicode_length) const {
if (idx == kDexNoIndex) {
*unicode_length = 0;
return NULL;
}
const StringId& string_id = GetStringId(idx);
return GetStringData(string_id, unicode_length);
}
const char* dexStringById(uint32_t idx) const {
int32_t unicode_length;
return dexStringById(idx, &unicode_length);
}
String* dexArtStringById(int32_t idx) const;
// Get the descriptor string associated with a given type index.
const char* dexStringByTypeIdx(uint32_t idx, int32_t* unicode_length) const {
const TypeId& type_id = GetTypeId(idx);
return dexStringById(type_id.descriptor_idx_, unicode_length);
}
const char* dexStringByTypeIdx(uint32_t idx) const {
const TypeId& type_id = GetTypeId(idx);
return dexStringById(type_id.descriptor_idx_);
}
String* dexArtStringByTypeIdx(int32_t idx) const {
const TypeId& type_id = GetTypeId(idx);
return dexArtStringById(type_id.descriptor_idx_);
}
// TODO: encoded_field is actually a stream of bytes
void dexReadClassDataField(const byte** encoded_field,
DexFile::Field* field,
uint32_t* last_idx) const {
uint32_t idx = *last_idx + DecodeUnsignedLeb128(encoded_field);
field->access_flags_ = DecodeUnsignedLeb128(encoded_field);
field->field_idx_ = idx;
*last_idx = idx;
}
// TODO: encoded_method is actually a stream of bytes
void dexReadClassDataMethod(const byte** encoded_method,
DexFile::Method* method,
uint32_t* last_idx) const {
uint32_t idx = *last_idx + DecodeUnsignedLeb128(encoded_method);
method->access_flags_ = DecodeUnsignedLeb128(encoded_method);
method->code_off_ = DecodeUnsignedLeb128(encoded_method);
method->method_idx_ = idx;
*last_idx = idx;
}
static const TryItem* dexGetTryItems(const CodeItem& code_item, uint32_t offset) {
const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_];
return reinterpret_cast<const TryItem*>
(RoundUp(reinterpret_cast<uint32_t>(insns_end_), 4)) + offset;
}
// Get the base of the encoded data for the given DexCode.
static const byte* dexGetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
const byte* handler_data = reinterpret_cast<const byte*>
(dexGetTryItems(code_item, code_item.tries_size_));
return handler_data + offset;
}
// Find the handler associated with a given address, if any.
// Initializes the given iterator and returns true if a match is
// found. Returns end if there is no applicable handler.
static CatchHandlerIterator dexFindCatchHandler(const CodeItem& code_item, uint32_t address) {
CatchHandlerItem handler;
handler.address_ = -1;
int32_t offset = -1;
// Short-circuit the overwhelmingly common cases.
switch (code_item.tries_size_) {
case 0:
break;
case 1: {
const TryItem* tries = dexGetTryItems(code_item, 0);
uint32_t start = tries->start_addr_;
if (address < start)
break;
uint32_t end = start + tries->insn_count_;
if (address >= end)
break;
offset = tries->handler_off_;
break;
}
default:
offset = dexFindCatchHandlerOffset0(code_item, code_item.tries_size_, address);
}
if (offset >= 0) {
const byte* handler_data = dexGetCatchHandlerData(code_item, offset);
return CatchHandlerIterator(handler_data);
}
return CatchHandlerIterator();
}
static int32_t dexFindCatchHandlerOffset0(const CodeItem &code_item,
int32_t tries_size,
uint32_t address) {
// Note: Signed type is important for max and min.
int32_t min = 0;
int32_t max = tries_size - 1;
while (max >= min) {
int32_t guess = (min + max) >> 1;
const TryItem* pTry = dexGetTryItems(code_item, guess);
uint32_t start = pTry->start_addr_;
if (address < start) {
max = guess - 1;
continue;
}
uint32_t end = start + pTry->insn_count_;
if (address >= end) {
min = guess + 1;
continue;
}
// We have a winner!
return (int32_t) pTry->handler_off_;
}
// No match.
return -1;
}
// Get the pointer to the start of the debugging data
const byte* dexGetDebugInfoStream(const CodeItem* code_item) const {
if (code_item->debug_info_off_ == 0) {
return NULL;
} else {
return base_ + code_item->debug_info_off_;
}
}
// Callback for "new position table entry".
// Returning true causes the decoder to stop early.
typedef bool (*DexDebugNewPositionCb)(void* cnxt, uint32_t address, uint32_t line_num);
// Callback for "new locals table entry". "signature" is an empty string
// if no signature is available for an entry.
typedef void (*DexDebugNewLocalCb)(void* cnxt, uint16_t reg,
uint32_t startAddress,
uint32_t endAddress,
const String* name,
const String* descriptor,
const String* signature);
static bool LineNumForPcCb(void* cnxt, uint32_t address, uint32_t line_num) {
LineNumFromPcContext *context = (LineNumFromPcContext *)cnxt;
// We know that this callback will be called in
// ascending address order, so keep going until we find
// a match or we've just gone past it.
if (address > context->address_) {
// The line number from the previous positions callback
// wil be the final result.
return true;
} else {
context->line_num_ = line_num;
return address == context->address_;
}
}
// Debug info opcodes and constants
enum {
DBG_END_SEQUENCE = 0x00,
DBG_ADVANCE_PC = 0x01,
DBG_ADVANCE_LINE = 0x02,
DBG_START_LOCAL = 0x03,
DBG_START_LOCAL_EXTENDED = 0x04,
DBG_END_LOCAL = 0x05,
DBG_RESTART_LOCAL = 0x06,
DBG_SET_PROLOGUE_END = 0x07,
DBG_SET_EPILOGUE_BEGIN = 0x08,
DBG_SET_FILE = 0x09,
DBG_FIRST_SPECIAL = 0x0a,
DBG_LINE_BASE = -4,
DBG_LINE_RANGE = 15,
};
struct LocalInfo {
LocalInfo() : name_(NULL), descriptor_(NULL), signature_(NULL), start_address_(0), is_live_(false) {}
// E.g., list
const String* name_;
// E.g., Ljava/util/LinkedList;
const String* descriptor_;
// E.g., java.util.LinkedList<java.lang.Integer>
const String* signature_;
// PC location where the local is first defined.
uint16_t start_address_;
// Is the local defined and live.
bool is_live_;
private:
DISALLOW_COPY_AND_ASSIGN(LocalInfo);
};
struct LineNumFromPcContext {
LineNumFromPcContext(uint32_t address, uint32_t line_num) :
address_(address), line_num_(line_num) {}
uint32_t address_;
uint32_t line_num_;
private:
DISALLOW_COPY_AND_ASSIGN(LineNumFromPcContext);
};
void InvokeLocalCbIfLive(void* cnxt, int reg, uint32_t end_address,
LocalInfo* local_in_reg, DexDebugNewLocalCb local_cb) const {
if (local_cb != NULL && local_in_reg[reg].is_live_) {
local_cb(cnxt, reg, local_in_reg[reg].start_address_, end_address,
local_in_reg[reg].name_, local_in_reg[reg].descriptor_,
local_in_reg[reg].signature_);
}
}
// Determine the source file line number based on the program counter.
// "pc" is an offset, in 16-bit units, from the start of the method's code.
//
// Returns -1 if no match was found (possibly because the source files were
// compiled without "-g", so no line number information is present).
// Returns -2 for native methods (as expected in exception traces).
//
// This is used by runtime; therefore use art::Method not art::DexFile::Method.
int32_t GetLineNumFromPC(const art::Method* method, uint32_t rel_pc) const;
void dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* method,
DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb,
void* cnxt, const byte* stream, LocalInfo* local_in_reg) const;
void dexDecodeDebugInfo(const CodeItem* code_item, const art::Method *method,
DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb,
void* cnxt) const {
const byte* stream = dexGetDebugInfoStream(code_item);
LocalInfo local_in_reg[code_item->registers_size_];
if (stream != NULL) {
dexDecodeDebugInfo0(code_item, method, posCb, local_cb, cnxt, stream, local_in_reg);
}
for (int reg = 0; reg < code_item->registers_size_; reg++) {
InvokeLocalCbIfLive(cnxt, reg, code_item->insns_size_, local_in_reg, local_cb);
}
}
// TODO: const reference
uint32_t dexGetIndexForClassDef(const ClassDef* class_def) const {
CHECK_GE(class_def, class_defs_);
CHECK_LT(class_def, class_defs_ + header_->class_defs_size_);
return class_def - class_defs_;
}
const char* dexGetSourceFile(const ClassDef& class_def) const {
if (class_def.source_file_idx_ == 0xffffffff) {
return NULL;
} else {
return dexStringById(class_def.source_file_idx_);
}
}
void ChangePermissions(int prot) const;
private:
// Helper class to deallocate underlying storage.
class Closer {
public:
virtual ~Closer();
virtual void ChangePermissions(int prot) = 0;
};
// Helper class to deallocate mmap-backed .dex files.
class MmapCloser : public Closer {
public:
MmapCloser(void* addr, size_t length);
virtual ~MmapCloser();
virtual void ChangePermissions(int prot);
private:
void* addr_;
size_t length_;
};
// Helper class for deallocating new/delete-backed .dex files.
class PtrCloser : public Closer {
public:
PtrCloser(byte* addr);
virtual ~PtrCloser();
virtual void ChangePermissions(int prot);
private:
byte* addr_;
};
// Opens a .dex file at the given address.
static const DexFile* Open(const byte* dex_file,
size_t length,
const std::string& location,
Closer* closer);
DexFile(const byte* addr, size_t length, const std::string& location, Closer* closer)
: base_(addr),
length_(length),
location_(location),
closer_(closer),
dex_object_lock_("a dex_object_lock_"),
dex_object_(NULL),
header_(0),
string_ids_(0),
type_ids_(0),
field_ids_(0),
method_ids_(0),
proto_ids_(0),
class_defs_(0) {
CHECK(addr != NULL);
CHECK_GT(length, 0U);
CHECK(closer != NULL);
}
// Top-level initializer that calls other Init methods.
bool Init();
// Caches pointers into to the various file sections.
void InitMembers();
// Builds the index of descriptors to class definitions.
void InitIndex();
// Returns true if the byte string equals the magic value.
bool CheckMagic(const byte* magic);
// Returns true if the header magic is of the expected value.
bool IsMagicValid();
// The index of descriptors to class definitions.
typedef std::map<const StringPiece, const DexFile::ClassDef*> Index;
Index index_;
// The base address of the memory mapping.
const byte* base_;
// The size of the underlying memory allocation in bytes.
size_t length_;
// Typically the dex file name when available, alternatively some identifying string.
//
// The ClassLinker will use this to match DexFiles the boot class
// path to DexCache::GetLocation when loading from an image.
const std::string location_;
// Helper object to free the underlying allocation.
UniquePtr<Closer> closer_;
// A cached com.android.dex.Dex instance, possibly NULL. Use GetDexObject.
mutable Mutex dex_object_lock_;
mutable jobject dex_object_;
// Points to the header section.
const Header* header_;
// Points to the base of the string identifier list.
const StringId* string_ids_;
// Points to the base of the type identifier list.
const TypeId* type_ids_;
// Points to the base of the field identifier list.
const FieldId* field_ids_;
// Points to the base of the method identifier list.
const MethodId* method_ids_;
// Points to the base of the prototype identifier list.
const ProtoId* proto_ids_;
// Points to the base of the class definition list.
const ClassDef* class_defs_;
};
} // namespace art
#endif // ART_SRC_DEX_FILE_H_