blob: 0ed040eba5efd87039422832b5c0d4110bca524d [file] [log] [blame]
David Sehr7629f602016-08-07 16:01:51 -07001/*
2 * Copyright (C) 2016 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 * Implementation file of the dex file intermediate representation.
17 *
18 * Utilities for reading dex files into an internal representation,
19 * manipulating them, and writing them out.
20 */
21
22#include "dex_ir.h"
23
24#include <map>
25#include <vector>
26
27#include "dex_file.h"
28#include "dex_file-inl.h"
29#include "utils.h"
30
31namespace art {
32namespace dex_ir {
33
34namespace {
35static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
36 uint64_t value = 0;
37 for (uint32_t i = 0; i <= length; i++) {
38 value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
39 }
40 if (sign_extend) {
41 int shift = (7 - length) * 8;
42 return (static_cast<int64_t>(value) << shift) >> shift;
43 }
44 return value;
45}
46
47static bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) {
48 DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
49 std::vector<std::unique_ptr<PositionInfo>>& positions = debug_info->GetPositionInfo();
50 positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_)));
51 return false;
52}
53
54static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) {
55 DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
56 std::vector<std::unique_ptr<LocalInfo>>& locals = debug_info->GetLocalInfo();
Jeff Haoc3acfc52016-08-29 14:18:26 -070057 const char* name = entry.name_ != nullptr ? entry.name_ : "(null)";
David Sehr7629f602016-08-07 16:01:51 -070058 const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
59 locals.push_back(std::unique_ptr<LocalInfo>(
Jeff Haoc3acfc52016-08-29 14:18:26 -070060 new LocalInfo(name, entry.descriptor_, signature, entry.start_address_,
David Sehr7629f602016-08-07 16:01:51 -070061 entry.end_address_, entry.reg_)));
62}
63} // namespace
64
65Header::Header(const DexFile& dex_file) : dex_file_(dex_file) {
66 const DexFile::Header& disk_header = dex_file.GetHeader();
67 memcpy(magic_, disk_header.magic_, sizeof(magic_));
68 checksum_ = disk_header.checksum_;
69 // TODO(sehr): clearly the signature will need to be recomputed before dumping.
70 memcpy(signature_, disk_header.signature_, sizeof(signature_));
71 endian_tag_ = disk_header.endian_tag_;
72 file_size_ = disk_header.file_size_;
73 header_size_ = disk_header.header_size_;
74 link_size_ = disk_header.link_size_;
75 link_offset_ = disk_header.link_off_;
76 data_size_ = disk_header.data_size_;
77 data_offset_ = disk_header.data_off_;
78 // Walk the rest of the header fields.
79 string_ids_.SetOffset(disk_header.string_ids_off_);
80 for (uint32_t i = 0; i < dex_file_.NumStringIds(); ++i) {
81 string_ids_.AddWithPosition(i, new StringId(dex_file_.GetStringId(i), *this));
82 }
83 type_ids_.SetOffset(disk_header.type_ids_off_);
84 for (uint32_t i = 0; i < dex_file_.NumTypeIds(); ++i) {
85 type_ids_.AddWithPosition(i, new TypeId(dex_file_.GetTypeId(i), *this));
86 }
87 proto_ids_.SetOffset(disk_header.proto_ids_off_);
88 for (uint32_t i = 0; i < dex_file_.NumProtoIds(); ++i) {
89 proto_ids_.AddWithPosition(i, new ProtoId(dex_file_.GetProtoId(i), *this));
90 }
91 field_ids_.SetOffset(disk_header.field_ids_off_);
92 for (uint32_t i = 0; i < dex_file_.NumFieldIds(); ++i) {
93 field_ids_.AddWithPosition(i, new FieldId(dex_file_.GetFieldId(i), *this));
94 }
95 method_ids_.SetOffset(disk_header.method_ids_off_);
96 for (uint32_t i = 0; i < dex_file_.NumMethodIds(); ++i) {
97 method_ids_.AddWithPosition(i, new MethodId(dex_file_.GetMethodId(i), *this));
98 }
99 class_defs_.SetOffset(disk_header.class_defs_off_);
100 for (uint32_t i = 0; i < dex_file_.NumClassDefs(); ++i) {
101 class_defs_.AddWithPosition(i, new ClassDef(dex_file_.GetClassDef(i), *this));
102 }
103}
104
105ArrayItem::ArrayItem(Header& header, const uint8_t** data, uint8_t type, uint8_t length) {
106 Read(header, data, type, length);
107}
108
109ArrayItem::ArrayItem(Header& header, const uint8_t** data) {
110 const uint8_t encoded_value = *(*data)++;
111 Read(header, data, encoded_value & 0x1f, encoded_value >> 5);
112}
113
114void ArrayItem::Read(Header& header, const uint8_t** data, uint8_t type, uint8_t length) {
115 type_ = type;
116 switch (type_) {
117 case DexFile::kDexAnnotationByte:
118 item_.byte_val_ = static_cast<int8_t>(ReadVarWidth(data, length, false));
119 break;
120 case DexFile::kDexAnnotationShort:
121 item_.short_val_ = static_cast<int16_t>(ReadVarWidth(data, length, true));
122 break;
123 case DexFile::kDexAnnotationChar:
124 item_.char_val_ = static_cast<uint16_t>(ReadVarWidth(data, length, false));
125 break;
126 case DexFile::kDexAnnotationInt:
127 item_.int_val_ = static_cast<int32_t>(ReadVarWidth(data, length, true));
128 break;
129 case DexFile::kDexAnnotationLong:
130 item_.long_val_ = static_cast<int64_t>(ReadVarWidth(data, length, true));
131 break;
132 case DexFile::kDexAnnotationFloat: {
133 // Fill on right.
134 union {
135 float f;
136 uint32_t data;
137 } conv;
138 conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
139 item_.float_val_ = conv.f;
140 break;
141 }
142 case DexFile::kDexAnnotationDouble: {
143 // Fill on right.
144 union {
145 double d;
146 uint64_t data;
147 } conv;
148 conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
149 item_.double_val_ = conv.d;
150 break;
151 }
152 case DexFile::kDexAnnotationString: {
153 const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
154 item_.string_val_ = header.StringIds()[string_index].get();
155 break;
156 }
157 case DexFile::kDexAnnotationType: {
158 const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
159 item_.string_val_ = header.TypeIds()[string_index]->GetStringId();
160 break;
161 }
162 case DexFile::kDexAnnotationField:
163 case DexFile::kDexAnnotationEnum: {
164 const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
165 item_.field_val_ = header.FieldIds()[field_index].get();
166 break;
167 }
168 case DexFile::kDexAnnotationMethod: {
169 const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
170 item_.method_val_ = header.MethodIds()[method_index].get();
171 break;
172 }
173 case DexFile::kDexAnnotationArray: {
174 item_.annotation_array_val_ = new std::vector<std::unique_ptr<ArrayItem>>();
175 // Decode all elements.
176 const uint32_t size = DecodeUnsignedLeb128(data);
177 for (uint32_t i = 0; i < size; i++) {
178 item_.annotation_array_val_->push_back(
179 std::unique_ptr<ArrayItem>(new ArrayItem(header, data)));
180 }
181 break;
182 }
183 case DexFile::kDexAnnotationAnnotation: {
184 const uint32_t type_idx = DecodeUnsignedLeb128(data);
185 item_.annotation_annotation_val_.string_ = header.TypeIds()[type_idx]->GetStringId();
186 item_.annotation_annotation_val_.array_ = new std::vector<std::unique_ptr<NameValuePair>>();
187 // Decode all name=value pairs.
188 const uint32_t size = DecodeUnsignedLeb128(data);
189 for (uint32_t i = 0; i < size; i++) {
190 const uint32_t name_index = DecodeUnsignedLeb128(data);
191 item_.annotation_annotation_val_.array_->push_back(std::unique_ptr<NameValuePair>(
192 new NameValuePair(header.StringIds()[name_index].get(), new ArrayItem(header, data))));
193 }
194 break;
195 }
196 case DexFile::kDexAnnotationNull:
197 break;
198 case DexFile::kDexAnnotationBoolean:
199 item_.bool_val_ = (length != 0);
200 break;
201 default:
202 break;
203 }
204}
205
206ClassDef::ClassDef(const DexFile::ClassDef& disk_class_def, Header& header) {
207 class_type_ = header.TypeIds()[disk_class_def.class_idx_].get();
208 access_flags_ = disk_class_def.access_flags_;
Jeff Haoc3acfc52016-08-29 14:18:26 -0700209 superclass_ = header.GetTypeIdOrNullPtr(disk_class_def.superclass_idx_);
David Sehr7629f602016-08-07 16:01:51 -0700210
211 const DexFile::TypeList* type_list = header.GetDexFile().GetInterfacesList(disk_class_def);
212 interfaces_offset_ = disk_class_def.interfaces_off_;
213 if (type_list != nullptr) {
214 for (uint32_t index = 0; index < type_list->Size(); ++index) {
215 interfaces_.push_back(header.TypeIds()[type_list->GetTypeItem(index).type_idx_].get());
216 }
217 }
Jeff Haoc3acfc52016-08-29 14:18:26 -0700218 source_file_ = header.GetStringIdOrNullPtr(disk_class_def.source_file_idx_);
David Sehr7629f602016-08-07 16:01:51 -0700219 // Annotations.
220 const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
221 header.GetDexFile().GetAnnotationsDirectory(disk_class_def);
222 if (disk_annotations_directory_item == nullptr) {
223 annotations_.reset(nullptr);
224 } else {
225 annotations_.reset(new AnnotationsDirectoryItem(disk_annotations_directory_item, header));
226 annotations_->SetOffset(disk_class_def.annotations_off_);
227 }
228 // Static field initializers.
229 static_values_ = nullptr;
230 const uint8_t* static_data = header.GetDexFile().GetEncodedStaticFieldValuesArray(disk_class_def);
231 if (static_data != nullptr) {
232 uint32_t static_value_count = static_data == nullptr ? 0 : DecodeUnsignedLeb128(&static_data);
233 if (static_value_count > 0) {
234 static_values_ = new std::vector<std::unique_ptr<ArrayItem>>();
235 for (uint32_t i = 0; i < static_value_count; ++i) {
236 static_values_->push_back(std::unique_ptr<ArrayItem>(new ArrayItem(header, &static_data)));
237 }
238 }
239 }
240 // Read the fields and methods defined by the class, resolving the circular reference from those
241 // to classes by setting class at the same time.
242 const uint8_t* encoded_data = header.GetDexFile().GetClassData(disk_class_def);
243 class_data_.SetOffset(disk_class_def.class_data_off_);
244 if (encoded_data != nullptr) {
245 ClassDataItemIterator cdii(header.GetDexFile(), encoded_data);
246 // Static fields.
247 for (uint32_t i = 0; cdii.HasNextStaticField(); i++, cdii.Next()) {
248 FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get();
249 uint32_t access_flags = cdii.GetRawMemberAccessFlags();
250 class_data_.StaticFields().push_back(
251 std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
252 }
253 // Instance fields.
254 for (uint32_t i = 0; cdii.HasNextInstanceField(); i++, cdii.Next()) {
255 FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get();
256 uint32_t access_flags = cdii.GetRawMemberAccessFlags();
257 class_data_.InstanceFields().push_back(
258 std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
259 }
260 // Direct methods.
261 for (uint32_t i = 0; cdii.HasNextDirectMethod(); i++, cdii.Next()) {
David Sehr7629f602016-08-07 16:01:51 -0700262 class_data_.DirectMethods().push_back(
Jeff Haoc3acfc52016-08-29 14:18:26 -0700263 std::unique_ptr<MethodItem>(GenerateMethodItem(header, cdii)));
David Sehr7629f602016-08-07 16:01:51 -0700264 }
265 // Virtual methods.
266 for (uint32_t i = 0; cdii.HasNextVirtualMethod(); i++, cdii.Next()) {
David Sehr7629f602016-08-07 16:01:51 -0700267 class_data_.VirtualMethods().push_back(
Jeff Haoc3acfc52016-08-29 14:18:26 -0700268 std::unique_ptr<MethodItem>(GenerateMethodItem(header, cdii)));
David Sehr7629f602016-08-07 16:01:51 -0700269 }
270 }
271}
272
Jeff Haoc3acfc52016-08-29 14:18:26 -0700273MethodItem* ClassDef::GenerateMethodItem(Header& header, ClassDataItemIterator& cdii) {
274 MethodId* method_item = header.MethodIds()[cdii.GetMemberIndex()].get();
275 uint32_t access_flags = cdii.GetRawMemberAccessFlags();
276 const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
277 CodeItem* code_item = nullptr;
278 DebugInfoItem* debug_info = nullptr;
279 if (disk_code_item != nullptr) {
280 code_item = new CodeItem(*disk_code_item, header);
281 code_item->SetOffset(cdii.GetMethodCodeItemOffset());
282 debug_info = code_item->DebugInfo();
283 }
284 if (debug_info != nullptr) {
285 bool is_static = (access_flags & kAccStatic) != 0;
286 header.GetDexFile().DecodeDebugLocalInfo(
287 disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info);
288 header.GetDexFile().DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info);
289 }
290 return new MethodItem(access_flags, method_item, code_item);
291}
292
David Sehr7629f602016-08-07 16:01:51 -0700293CodeItem::CodeItem(const DexFile::CodeItem& disk_code_item, Header& header) {
294 registers_size_ = disk_code_item.registers_size_;
295 ins_size_ = disk_code_item.ins_size_;
296 outs_size_ = disk_code_item.outs_size_;
297 tries_size_ = disk_code_item.tries_size_;
298
299 const uint8_t* debug_info_stream = header.GetDexFile().GetDebugInfoStream(&disk_code_item);
300 if (debug_info_stream != nullptr) {
301 debug_info_.reset(new DebugInfoItem());
302 } else {
303 debug_info_.reset(nullptr);
304 }
305
306 insns_size_ = disk_code_item.insns_size_in_code_units_;
307 insns_.reset(new uint16_t[insns_size_]);
308 memcpy(insns_.get(), disk_code_item.insns_, insns_size_ * sizeof(uint16_t));
309
310 if (tries_size_ > 0) {
311 tries_ = new std::vector<std::unique_ptr<const TryItem>>();
312 for (uint32_t i = 0; i < tries_size_; ++i) {
313 const DexFile::TryItem* disk_try_item = header.GetDexFile().GetTryItems(disk_code_item, i);
314 tries_->push_back(std::unique_ptr<const TryItem>(
315 new TryItem(*disk_try_item, disk_code_item, header)));
316 }
317 } else {
318 tries_ = nullptr;
319 }
320}
321
322AnnotationSetItem::AnnotationSetItem(const DexFile::AnnotationSetItem& disk_annotations_item,
323 Header& header) {
324 if (disk_annotations_item.size_ == 0) {
325 return;
326 }
327 for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
328 const DexFile::AnnotationItem* annotation =
329 header.GetDexFile().GetAnnotationItem(&disk_annotations_item, i);
330 if (annotation == nullptr) {
331 continue;
332 }
333 uint8_t visibility = annotation->visibility_;
334 const uint8_t* annotation_data = annotation->annotation_;
335 ArrayItem* array_item =
336 new ArrayItem(header, &annotation_data, DexFile::kDexAnnotationAnnotation, 0);
337 items_.push_back(std::unique_ptr<AnnotationItem>(new AnnotationItem(visibility, array_item)));
338 }
339}
340
341AnnotationsDirectoryItem::AnnotationsDirectoryItem(
342 const DexFile::AnnotationsDirectoryItem* disk_annotations_item, Header& header) {
343 const DexFile::AnnotationSetItem* class_set_item =
344 header.GetDexFile().GetClassAnnotationSet(disk_annotations_item);
345 if (class_set_item == nullptr) {
346 class_annotation_.reset(nullptr);
347 } else {
348 class_annotation_.reset(new AnnotationSetItem(*class_set_item, header));
349 }
350 const DexFile::FieldAnnotationsItem* fields =
351 header.GetDexFile().GetFieldAnnotations(disk_annotations_item);
352 if (fields != nullptr) {
353 for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
354 FieldId* field_id = header.FieldIds()[fields[i].field_idx_].get();
355 const DexFile::AnnotationSetItem* field_set_item =
356 header.GetDexFile().GetFieldAnnotationSetItem(fields[i]);
357 dex_ir::AnnotationSetItem* annotation_set_item =
358 new AnnotationSetItem(*field_set_item, header);
359 field_annotations_.push_back(std::unique_ptr<FieldAnnotation>(
360 new FieldAnnotation(field_id, annotation_set_item)));
361 }
362 }
363 const DexFile::MethodAnnotationsItem* methods =
364 header.GetDexFile().GetMethodAnnotations(disk_annotations_item);
365 if (methods != nullptr) {
366 for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
367 MethodId* method_id = header.MethodIds()[methods[i].method_idx_].get();
368 const DexFile::AnnotationSetItem* method_set_item =
369 header.GetDexFile().GetMethodAnnotationSetItem(methods[i]);
370 dex_ir::AnnotationSetItem* annotation_set_item =
371 new AnnotationSetItem(*method_set_item, header);
372 method_annotations_.push_back(std::unique_ptr<MethodAnnotation>(
373 new MethodAnnotation(method_id, annotation_set_item)));
374 }
375 }
376 const DexFile::ParameterAnnotationsItem* parameters =
377 header.GetDexFile().GetParameterAnnotations(disk_annotations_item);
378 if (parameters != nullptr) {
379 for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
380 MethodId* method_id = header.MethodIds()[parameters[i].method_idx_].get();
381 const DexFile::AnnotationSetRefList* list =
382 header.GetDexFile().GetParameterAnnotationSetRefList(&parameters[i]);
383 parameter_annotations_.push_back(std::unique_ptr<ParameterAnnotation>(
384 new ParameterAnnotation(method_id, list, header)));
385 }
386 }
387}
388
389} // namespace dex_ir
390} // namespace art