1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // TODO: Dex helpers have ART specific APIs, we may want to refactor these for use in dexdump.
18 
19 #ifndef ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_H_
20 #define ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_H_
21 
22 #include "compact_dex_file.h"
23 #include "dex_file.h"
24 #include "dex_instruction_iterator.h"
25 #include "standard_dex_file.h"
26 
27 namespace art {
28 
29 class ArtMethod;
30 
31 // Abstracts accesses to the instruction fields of code items for CompactDexFile and
32 // StandardDexFile.
33 class CodeItemInstructionAccessor {
34  public:
35   ALWAYS_INLINE CodeItemInstructionAccessor(const DexFile& dex_file,
36                                             const DexFile::CodeItem* code_item);
37 
38   ALWAYS_INLINE explicit CodeItemInstructionAccessor(ArtMethod* method);
39 
40   ALWAYS_INLINE DexInstructionIterator begin() const;
41 
42   ALWAYS_INLINE DexInstructionIterator end() const;
43 
44   IterationRange<DexInstructionIterator> InstructionsFrom(uint32_t start_dex_pc) const;
45 
InsnsSizeInCodeUnits()46   uint32_t InsnsSizeInCodeUnits() const {
47     return insns_size_in_code_units_;
48   }
49 
Insns()50   const uint16_t* Insns() const {
51     return insns_;
52   }
53 
54   // Return the instruction for a dex pc.
InstructionAt(uint32_t dex_pc)55   const Instruction& InstructionAt(uint32_t dex_pc) const {
56     DCHECK_LT(dex_pc, InsnsSizeInCodeUnits());
57     return *Instruction::At(insns_ + dex_pc);
58   }
59 
60   // Return true if the accessor has a code item.
HasCodeItem()61   bool HasCodeItem() const {
62     return Insns() != nullptr;
63   }
64 
65  protected:
66   CodeItemInstructionAccessor() = default;
67 
68   ALWAYS_INLINE void Init(uint32_t insns_size_in_code_units, const uint16_t* insns);
69   ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
70   ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
71   ALWAYS_INLINE void Init(const DexFile& dex_file, const DexFile::CodeItem* code_item);
72 
73  private:
74   // size of the insns array, in 2 byte code units. 0 if there is no code item.
75   uint32_t insns_size_in_code_units_ = 0;
76 
77   // Pointer to the instructions, null if there is no code item.
78   const uint16_t* insns_ = 0;
79 };
80 
81 // Abstracts accesses to code item fields other than debug info for CompactDexFile and
82 // StandardDexFile.
83 class CodeItemDataAccessor : public CodeItemInstructionAccessor {
84  public:
85   ALWAYS_INLINE CodeItemDataAccessor(const DexFile& dex_file, const DexFile::CodeItem* code_item);
86 
RegistersSize()87   uint16_t RegistersSize() const {
88     return registers_size_;
89   }
90 
InsSize()91   uint16_t InsSize() const {
92     return ins_size_;
93   }
94 
OutsSize()95   uint16_t OutsSize() const {
96     return outs_size_;
97   }
98 
TriesSize()99   uint16_t TriesSize() const {
100     return tries_size_;
101   }
102 
103   IterationRange<const DexFile::TryItem*> TryItems() const;
104 
105   const uint8_t* GetCatchHandlerData(size_t offset = 0) const;
106 
107   const DexFile::TryItem* FindTryItem(uint32_t try_dex_pc) const;
108 
109   inline const void* CodeItemDataEnd() const;
110 
111  protected:
112   CodeItemDataAccessor() = default;
113 
114   ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
115   ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
116   ALWAYS_INLINE void Init(const DexFile& dex_file, const DexFile::CodeItem* code_item);
117 
118  private:
119   // Fields mirrored from the dex/cdex code item.
120   uint16_t registers_size_;
121   uint16_t ins_size_;
122   uint16_t outs_size_;
123   uint16_t tries_size_;
124 };
125 
126 // Abstract accesses to code item data including debug info offset. More heavy weight than the other
127 // helpers.
128 class CodeItemDebugInfoAccessor : public CodeItemDataAccessor {
129  public:
130   CodeItemDebugInfoAccessor() = default;
131 
132   // Initialize with an existing offset.
CodeItemDebugInfoAccessor(const DexFile & dex_file,const DexFile::CodeItem * code_item,uint32_t dex_method_index)133   ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile& dex_file,
134                                           const DexFile::CodeItem* code_item,
135                                           uint32_t dex_method_index) {
136     Init(dex_file, code_item, dex_method_index);
137   }
138 
139   ALWAYS_INLINE void Init(const DexFile& dex_file,
140                           const DexFile::CodeItem* code_item,
141                           uint32_t dex_method_index);
142 
143   ALWAYS_INLINE explicit CodeItemDebugInfoAccessor(ArtMethod* method);
144 
DebugInfoOffset()145   uint32_t DebugInfoOffset() const {
146     return debug_info_offset_;
147   }
148 
149   template<typename NewLocalCallback>
150   bool DecodeDebugLocalInfo(bool is_static,
151                             uint32_t method_idx,
152                             NewLocalCallback new_local,
153                             void* context) const;
154 
155  protected:
156   ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item, uint32_t dex_method_index);
157   ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
158 
159  private:
160   const DexFile* dex_file_ = nullptr;
161   uint32_t debug_info_offset_ = 0u;
162 };
163 
164 }  // namespace art
165 
166 #endif  // ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_H_
167