Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 1 | /* |
| 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 | * Header file of an in-memory representation of DEX files. |
| 17 | */ |
| 18 | |
| 19 | #include <stdint.h> |
| 20 | |
| 21 | #include <queue> |
| 22 | #include <vector> |
| 23 | |
| 24 | #include "dex_writer.h" |
| 25 | #include "utf.h" |
| 26 | |
| 27 | namespace art { |
| 28 | |
| 29 | size_t EncodeIntValue(int32_t value, uint8_t* buffer) { |
| 30 | size_t length = 0; |
| 31 | if (value >= 0) { |
| 32 | while (value > 0x7f) { |
| 33 | buffer[length++] = static_cast<uint8_t>(value); |
| 34 | value >>= 8; |
| 35 | } |
| 36 | } else { |
| 37 | while (value < -0x80) { |
| 38 | buffer[length++] = static_cast<uint8_t>(value); |
| 39 | value >>= 8; |
| 40 | } |
| 41 | } |
| 42 | buffer[length++] = static_cast<uint8_t>(value); |
| 43 | return length; |
| 44 | } |
| 45 | |
| 46 | size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) { |
| 47 | size_t length = 0; |
| 48 | do { |
| 49 | buffer[length++] = static_cast<uint8_t>(value); |
| 50 | value >>= 8; |
| 51 | } while (value != 0); |
| 52 | return length; |
| 53 | } |
| 54 | |
| 55 | size_t EncodeLongValue(int64_t value, uint8_t* buffer) { |
| 56 | size_t length = 0; |
| 57 | if (value >= 0) { |
| 58 | while (value > 0x7f) { |
| 59 | buffer[length++] = static_cast<uint8_t>(value); |
| 60 | value >>= 8; |
| 61 | } |
| 62 | } else { |
| 63 | while (value < -0x80) { |
| 64 | buffer[length++] = static_cast<uint8_t>(value); |
| 65 | value >>= 8; |
| 66 | } |
| 67 | } |
| 68 | buffer[length++] = static_cast<uint8_t>(value); |
| 69 | return length; |
| 70 | } |
| 71 | |
| 72 | union FloatUnion { |
| 73 | float f_; |
| 74 | uint32_t i_; |
| 75 | }; |
| 76 | |
| 77 | size_t EncodeFloatValue(float value, uint8_t* buffer) { |
| 78 | FloatUnion float_union; |
| 79 | float_union.f_ = value; |
| 80 | uint32_t int_value = float_union.i_; |
| 81 | size_t index = 3; |
| 82 | do { |
| 83 | buffer[index--] = int_value >> 24; |
| 84 | int_value <<= 8; |
| 85 | } while (int_value != 0); |
| 86 | return 3 - index; |
| 87 | } |
| 88 | |
| 89 | union DoubleUnion { |
| 90 | double d_; |
| 91 | uint64_t l_; |
| 92 | }; |
| 93 | |
| 94 | size_t EncodeDoubleValue(double value, uint8_t* buffer) { |
| 95 | DoubleUnion double_union; |
| 96 | double_union.d_ = value; |
| 97 | uint64_t long_value = double_union.l_; |
| 98 | size_t index = 7; |
| 99 | do { |
| 100 | buffer[index--] = long_value >> 56; |
| 101 | long_value <<= 8; |
| 102 | } while (long_value != 0); |
| 103 | return 7 - index; |
| 104 | } |
| 105 | |
| 106 | size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) { |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 107 | DCHECK_LE(offset + length, mem_map_->Size()); |
| 108 | memcpy(mem_map_->Begin() + offset, buffer, length); |
| 109 | return length; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) { |
| 113 | uint8_t buffer[8]; |
| 114 | EncodeSignedLeb128(buffer, value); |
| 115 | return Write(buffer, SignedLeb128Size(value), offset); |
| 116 | } |
| 117 | |
| 118 | size_t DexWriter::WriteUleb128(uint32_t value, size_t offset) { |
| 119 | uint8_t buffer[8]; |
| 120 | EncodeUnsignedLeb128(buffer, value); |
| 121 | return Write(buffer, UnsignedLeb128Size(value), offset); |
| 122 | } |
| 123 | |
| 124 | size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) { |
| 125 | size_t original_offset = offset; |
| 126 | size_t start = 0; |
| 127 | size_t length; |
| 128 | uint8_t buffer[8]; |
| 129 | int8_t type = encoded_value->Type(); |
| 130 | switch (type) { |
| 131 | case DexFile::kDexAnnotationByte: |
| 132 | length = EncodeIntValue(encoded_value->GetByte(), buffer); |
| 133 | break; |
| 134 | case DexFile::kDexAnnotationShort: |
| 135 | length = EncodeIntValue(encoded_value->GetShort(), buffer); |
| 136 | break; |
| 137 | case DexFile::kDexAnnotationChar: |
| 138 | length = EncodeUIntValue(encoded_value->GetChar(), buffer); |
| 139 | break; |
| 140 | case DexFile::kDexAnnotationInt: |
| 141 | length = EncodeIntValue(encoded_value->GetInt(), buffer); |
| 142 | break; |
| 143 | case DexFile::kDexAnnotationLong: |
| 144 | length = EncodeLongValue(encoded_value->GetLong(), buffer); |
| 145 | break; |
| 146 | case DexFile::kDexAnnotationFloat: |
| 147 | length = EncodeFloatValue(encoded_value->GetFloat(), buffer); |
| 148 | start = 4 - length; |
| 149 | break; |
| 150 | case DexFile::kDexAnnotationDouble: |
| 151 | length = EncodeDoubleValue(encoded_value->GetDouble(), buffer); |
| 152 | start = 8 - length; |
| 153 | break; |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame^] | 154 | case DexFile::kDexAnnotationMethodType: |
| 155 | length = EncodeUIntValue(encoded_value->GetProtoId()->GetIndex(), buffer); |
| 156 | break; |
| 157 | case DexFile::kDexAnnotationMethodHandle: |
| 158 | length = EncodeUIntValue(encoded_value->GetMethodHandle()->GetIndex(), buffer); |
| 159 | break; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 160 | case DexFile::kDexAnnotationString: |
| 161 | length = EncodeUIntValue(encoded_value->GetStringId()->GetIndex(), buffer); |
| 162 | break; |
| 163 | case DexFile::kDexAnnotationType: |
| 164 | length = EncodeUIntValue(encoded_value->GetTypeId()->GetIndex(), buffer); |
| 165 | break; |
| 166 | case DexFile::kDexAnnotationField: |
| 167 | case DexFile::kDexAnnotationEnum: |
| 168 | length = EncodeUIntValue(encoded_value->GetFieldId()->GetIndex(), buffer); |
| 169 | break; |
| 170 | case DexFile::kDexAnnotationMethod: |
| 171 | length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer); |
| 172 | break; |
| 173 | case DexFile::kDexAnnotationArray: |
| 174 | offset += WriteEncodedValueHeader(type, 0, offset); |
| 175 | offset += WriteEncodedArray(encoded_value->GetEncodedArray()->GetEncodedValues(), offset); |
| 176 | return offset - original_offset; |
| 177 | case DexFile::kDexAnnotationAnnotation: |
| 178 | offset += WriteEncodedValueHeader(type, 0, offset); |
| 179 | offset += WriteEncodedAnnotation(encoded_value->GetEncodedAnnotation(), offset); |
| 180 | return offset - original_offset; |
| 181 | case DexFile::kDexAnnotationNull: |
| 182 | return WriteEncodedValueHeader(type, 0, offset); |
| 183 | case DexFile::kDexAnnotationBoolean: |
| 184 | return WriteEncodedValueHeader(type, encoded_value->GetBoolean() ? 1 : 0, offset); |
| 185 | default: |
| 186 | return 0; |
| 187 | } |
| 188 | offset += WriteEncodedValueHeader(type, length - 1, offset); |
| 189 | offset += Write(buffer + start, length, offset); |
| 190 | return offset - original_offset; |
| 191 | } |
| 192 | |
| 193 | size_t DexWriter::WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) { |
| 194 | uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) }; |
| 195 | return Write(buffer, sizeof(uint8_t), offset); |
| 196 | } |
| 197 | |
| 198 | size_t DexWriter::WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) { |
| 199 | size_t original_offset = offset; |
| 200 | offset += WriteUleb128(values->size(), offset); |
| 201 | for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) { |
| 202 | offset += WriteEncodedValue(value.get(), offset); |
| 203 | } |
| 204 | return offset - original_offset; |
| 205 | } |
| 206 | |
| 207 | size_t DexWriter::WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) { |
| 208 | size_t original_offset = offset; |
| 209 | offset += WriteUleb128(annotation->GetType()->GetIndex(), offset); |
| 210 | offset += WriteUleb128(annotation->GetAnnotationElements()->size(), offset); |
| 211 | for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element : |
| 212 | *annotation->GetAnnotationElements()) { |
| 213 | offset += WriteUleb128(annotation_element->GetName()->GetIndex(), offset); |
| 214 | offset += WriteEncodedValue(annotation_element->GetValue(), offset); |
| 215 | } |
| 216 | return offset - original_offset; |
| 217 | } |
| 218 | |
| 219 | size_t DexWriter::WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) { |
| 220 | size_t original_offset = offset; |
| 221 | uint32_t prev_index = 0; |
| 222 | for (std::unique_ptr<dex_ir::FieldItem>& field : *fields) { |
| 223 | uint32_t index = field->GetFieldId()->GetIndex(); |
| 224 | offset += WriteUleb128(index - prev_index, offset); |
| 225 | offset += WriteUleb128(field->GetAccessFlags(), offset); |
| 226 | prev_index = index; |
| 227 | } |
| 228 | return offset - original_offset; |
| 229 | } |
| 230 | |
| 231 | size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) { |
| 232 | size_t original_offset = offset; |
| 233 | uint32_t prev_index = 0; |
| 234 | for (std::unique_ptr<dex_ir::MethodItem>& method : *methods) { |
| 235 | uint32_t index = method->GetMethodId()->GetIndex(); |
| 236 | uint32_t code_off = method->GetCodeItem() == nullptr ? 0 : method->GetCodeItem()->GetOffset(); |
| 237 | offset += WriteUleb128(index - prev_index, offset); |
| 238 | offset += WriteUleb128(method->GetAccessFlags(), offset); |
| 239 | offset += WriteUleb128(code_off, offset); |
| 240 | prev_index = index; |
| 241 | } |
| 242 | return offset - original_offset; |
| 243 | } |
| 244 | |
| 245 | void DexWriter::WriteStrings() { |
| 246 | uint32_t string_data_off[1]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 247 | for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 248 | string_data_off[0] = string_id->DataItem()->GetOffset(); |
| 249 | Write(string_data_off, string_id->GetSize(), string_id->GetOffset()); |
| 250 | } |
| 251 | |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 252 | for (auto& string_data_pair : header_->GetCollections().StringDatas()) { |
| 253 | std::unique_ptr<dex_ir::StringData>& string_data = string_data_pair.second; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 254 | uint32_t offset = string_data->GetOffset(); |
| 255 | offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset); |
| 256 | Write(string_data->Data(), strlen(string_data->Data()), offset); |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | void DexWriter::WriteTypes() { |
| 261 | uint32_t descriptor_idx[1]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 262 | for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 263 | descriptor_idx[0] = type_id->GetStringId()->GetIndex(); |
| 264 | Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset()); |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | void DexWriter::WriteTypeLists() { |
| 269 | uint32_t size[1]; |
| 270 | uint16_t list[1]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 271 | for (auto& type_list_pair : header_->GetCollections().TypeLists()) { |
| 272 | std::unique_ptr<dex_ir::TypeList>& type_list = type_list_pair.second; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 273 | size[0] = type_list->GetTypeList()->size(); |
| 274 | uint32_t offset = type_list->GetOffset(); |
| 275 | offset += Write(size, sizeof(uint32_t), offset); |
| 276 | for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) { |
| 277 | list[0] = type_id->GetIndex(); |
| 278 | offset += Write(list, sizeof(uint16_t), offset); |
| 279 | } |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | void DexWriter::WriteProtos() { |
| 284 | uint32_t buffer[3]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 285 | for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 286 | buffer[0] = proto_id->Shorty()->GetIndex(); |
| 287 | buffer[1] = proto_id->ReturnType()->GetIndex(); |
| 288 | buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset(); |
| 289 | Write(buffer, proto_id->GetSize(), proto_id->GetOffset()); |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | void DexWriter::WriteFields() { |
| 294 | uint16_t buffer[4]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 295 | for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 296 | buffer[0] = field_id->Class()->GetIndex(); |
| 297 | buffer[1] = field_id->Type()->GetIndex(); |
| 298 | buffer[2] = field_id->Name()->GetIndex(); |
| 299 | buffer[3] = field_id->Name()->GetIndex() >> 16; |
| 300 | Write(buffer, field_id->GetSize(), field_id->GetOffset()); |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | void DexWriter::WriteMethods() { |
| 305 | uint16_t buffer[4]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 306 | for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 307 | buffer[0] = method_id->Class()->GetIndex(); |
| 308 | buffer[1] = method_id->Proto()->GetIndex(); |
| 309 | buffer[2] = method_id->Name()->GetIndex(); |
| 310 | buffer[3] = method_id->Name()->GetIndex() >> 16; |
| 311 | Write(buffer, method_id->GetSize(), method_id->GetOffset()); |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | void DexWriter::WriteEncodedArrays() { |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 316 | for (auto& encoded_array_pair : header_->GetCollections().EncodedArrayItems()) { |
| 317 | std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array = encoded_array_pair.second; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 318 | WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset()); |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | void DexWriter::WriteAnnotations() { |
| 323 | uint8_t visibility[1]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 324 | for (auto& annotation_pair : header_->GetCollections().AnnotationItems()) { |
| 325 | std::unique_ptr<dex_ir::AnnotationItem>& annotation = annotation_pair.second; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 326 | visibility[0] = annotation->GetVisibility(); |
| 327 | size_t offset = annotation->GetOffset(); |
| 328 | offset += Write(visibility, sizeof(uint8_t), offset); |
| 329 | WriteEncodedAnnotation(annotation->GetAnnotation(), offset); |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | void DexWriter::WriteAnnotationSets() { |
| 334 | uint32_t size[1]; |
| 335 | uint32_t annotation_off[1]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 336 | for (auto& annotation_set_pair : header_->GetCollections().AnnotationSetItems()) { |
| 337 | std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set = annotation_set_pair.second; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 338 | size[0] = annotation_set->GetItems()->size(); |
| 339 | size_t offset = annotation_set->GetOffset(); |
| 340 | offset += Write(size, sizeof(uint32_t), offset); |
| 341 | for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) { |
| 342 | annotation_off[0] = annotation->GetOffset(); |
| 343 | offset += Write(annotation_off, sizeof(uint32_t), offset); |
| 344 | } |
| 345 | } |
| 346 | } |
| 347 | |
| 348 | void DexWriter::WriteAnnotationSetRefs() { |
| 349 | uint32_t size[1]; |
| 350 | uint32_t annotations_off[1]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 351 | for (auto& anno_set_ref_pair : header_->GetCollections().AnnotationSetRefLists()) { |
| 352 | std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref = anno_set_ref_pair.second; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 353 | size[0] = annotation_set_ref->GetItems()->size(); |
| 354 | size_t offset = annotation_set_ref->GetOffset(); |
| 355 | offset += Write(size, sizeof(uint32_t), offset); |
| 356 | for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) { |
| 357 | annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset(); |
| 358 | offset += Write(annotations_off, sizeof(uint32_t), offset); |
| 359 | } |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | void DexWriter::WriteAnnotationsDirectories() { |
| 364 | uint32_t directory_buffer[4]; |
| 365 | uint32_t annotation_buffer[2]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 366 | for (auto& annotations_directory_pair : header_->GetCollections().AnnotationsDirectoryItems()) { |
| 367 | std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory = |
| 368 | annotations_directory_pair.second; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 369 | directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 : |
| 370 | annotations_directory->GetClassAnnotation()->GetOffset(); |
| 371 | directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 : |
| 372 | annotations_directory->GetFieldAnnotations()->size(); |
| 373 | directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 : |
| 374 | annotations_directory->GetMethodAnnotations()->size(); |
| 375 | directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 : |
| 376 | annotations_directory->GetParameterAnnotations()->size(); |
| 377 | uint32_t offset = annotations_directory->GetOffset(); |
| 378 | offset += Write(directory_buffer, 4 * sizeof(uint32_t), offset); |
| 379 | if (annotations_directory->GetFieldAnnotations() != nullptr) { |
| 380 | for (std::unique_ptr<dex_ir::FieldAnnotation>& field : |
| 381 | *annotations_directory->GetFieldAnnotations()) { |
| 382 | annotation_buffer[0] = field->GetFieldId()->GetIndex(); |
| 383 | annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset(); |
| 384 | offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); |
| 385 | } |
| 386 | } |
| 387 | if (annotations_directory->GetMethodAnnotations() != nullptr) { |
| 388 | for (std::unique_ptr<dex_ir::MethodAnnotation>& method : |
| 389 | *annotations_directory->GetMethodAnnotations()) { |
| 390 | annotation_buffer[0] = method->GetMethodId()->GetIndex(); |
| 391 | annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset(); |
| 392 | offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); |
| 393 | } |
| 394 | } |
| 395 | if (annotations_directory->GetParameterAnnotations() != nullptr) { |
| 396 | for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter : |
| 397 | *annotations_directory->GetParameterAnnotations()) { |
| 398 | annotation_buffer[0] = parameter->GetMethodId()->GetIndex(); |
| 399 | annotation_buffer[1] = parameter->GetAnnotations()->GetOffset(); |
| 400 | offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); |
| 401 | } |
| 402 | } |
| 403 | } |
| 404 | } |
| 405 | |
| 406 | void DexWriter::WriteDebugInfoItems() { |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 407 | for (auto& debug_info_pair : header_->GetCollections().DebugInfoItems()) { |
| 408 | std::unique_ptr<dex_ir::DebugInfoItem>& debug_info = debug_info_pair.second; |
| 409 | Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), debug_info->GetOffset()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 410 | } |
| 411 | } |
| 412 | |
| 413 | void DexWriter::WriteCodeItems() { |
| 414 | uint16_t uint16_buffer[4]; |
| 415 | uint32_t uint32_buffer[2]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 416 | for (auto& code_item_pair : header_->GetCollections().CodeItems()) { |
| 417 | std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 418 | uint16_buffer[0] = code_item->RegistersSize(); |
| 419 | uint16_buffer[1] = code_item->InsSize(); |
| 420 | uint16_buffer[2] = code_item->OutsSize(); |
| 421 | uint16_buffer[3] = code_item->TriesSize(); |
| 422 | uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 : code_item->DebugInfo()->GetOffset(); |
| 423 | uint32_buffer[1] = code_item->InsnsSize(); |
| 424 | size_t offset = code_item->GetOffset(); |
| 425 | offset += Write(uint16_buffer, 4 * sizeof(uint16_t), offset); |
| 426 | offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset); |
| 427 | offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset); |
| 428 | if (code_item->TriesSize() != 0) { |
| 429 | if (code_item->InsnsSize() % 2 != 0) { |
| 430 | uint16_t padding[1] = { 0 }; |
| 431 | offset += Write(padding, sizeof(uint16_t), offset); |
| 432 | } |
| 433 | uint32_t start_addr[1]; |
| 434 | uint16_t insn_count_and_handler_off[2]; |
| 435 | for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) { |
| 436 | start_addr[0] = try_item->StartAddr(); |
| 437 | insn_count_and_handler_off[0] = try_item->InsnCount(); |
| 438 | insn_count_and_handler_off[1] = try_item->GetHandlers()->GetListOffset(); |
| 439 | offset += Write(start_addr, sizeof(uint32_t), offset); |
| 440 | offset += Write(insn_count_and_handler_off, 2 * sizeof(uint16_t), offset); |
| 441 | } |
| 442 | // Leave offset pointing to the end of the try items. |
| 443 | WriteUleb128(code_item->Handlers()->size(), offset); |
| 444 | for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) { |
| 445 | size_t list_offset = offset + handlers->GetListOffset(); |
| 446 | uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 : |
| 447 | handlers->GetHandlers()->size(); |
| 448 | list_offset += WriteSleb128(size, list_offset); |
| 449 | for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) { |
| 450 | if (handler->GetTypeId() != nullptr) { |
| 451 | list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset); |
| 452 | } |
| 453 | list_offset += WriteUleb128(handler->GetAddress(), list_offset); |
| 454 | } |
| 455 | } |
| 456 | } |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | void DexWriter::WriteClasses() { |
| 461 | uint32_t class_def_buffer[8]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 462 | for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 463 | class_def_buffer[0] = class_def->ClassType()->GetIndex(); |
| 464 | class_def_buffer[1] = class_def->GetAccessFlags(); |
| 465 | class_def_buffer[2] = class_def->Superclass() == nullptr ? DexFile::kDexNoIndex : |
| 466 | class_def->Superclass()->GetIndex(); |
| 467 | class_def_buffer[3] = class_def->InterfacesOffset(); |
| 468 | class_def_buffer[4] = class_def->SourceFile() == nullptr ? DexFile::kDexNoIndex : |
| 469 | class_def->SourceFile()->GetIndex(); |
| 470 | class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 : |
| 471 | class_def->Annotations()->GetOffset(); |
| 472 | class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 : |
| 473 | class_def->GetClassData()->GetOffset(); |
| 474 | class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 : |
| 475 | class_def->StaticValues()->GetOffset(); |
| 476 | size_t offset = class_def->GetOffset(); |
| 477 | Write(class_def_buffer, class_def->GetSize(), offset); |
| 478 | } |
| 479 | |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 480 | for (auto& class_data_pair : header_->GetCollections().ClassDatas()) { |
| 481 | std::unique_ptr<dex_ir::ClassData>& class_data = class_data_pair.second; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 482 | size_t offset = class_data->GetOffset(); |
| 483 | offset += WriteUleb128(class_data->StaticFields()->size(), offset); |
| 484 | offset += WriteUleb128(class_data->InstanceFields()->size(), offset); |
| 485 | offset += WriteUleb128(class_data->DirectMethods()->size(), offset); |
| 486 | offset += WriteUleb128(class_data->VirtualMethods()->size(), offset); |
| 487 | offset += WriteEncodedFields(class_data->StaticFields(), offset); |
| 488 | offset += WriteEncodedFields(class_data->InstanceFields(), offset); |
| 489 | offset += WriteEncodedMethods(class_data->DirectMethods(), offset); |
| 490 | offset += WriteEncodedMethods(class_data->VirtualMethods(), offset); |
| 491 | } |
| 492 | } |
| 493 | |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame^] | 494 | void DexWriter::WriteCallSites() { |
| 495 | uint32_t call_site_off[1]; |
| 496 | for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id : |
| 497 | header_->GetCollections().CallSiteIds()) { |
| 498 | call_site_off[0] = call_site_id->CallSiteItem()->GetOffset(); |
| 499 | Write(call_site_off, call_site_id->GetSize(), call_site_id->GetOffset()); |
| 500 | } |
| 501 | } |
| 502 | |
| 503 | void DexWriter::WriteMethodHandles() { |
| 504 | uint16_t method_handle_buff[4]; |
| 505 | for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle : |
| 506 | header_->GetCollections().MethodHandleItems()) { |
| 507 | method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType()); |
| 508 | method_handle_buff[1] = 0; // unused. |
| 509 | method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex(); |
| 510 | method_handle_buff[3] = 0; // unused. |
| 511 | Write(method_handle_buff, method_handle->GetSize(), method_handle->GetOffset()); |
| 512 | } |
| 513 | } |
| 514 | |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 515 | struct MapItemContainer { |
| 516 | MapItemContainer(uint32_t type, uint32_t size, uint32_t offset) |
| 517 | : type_(type), size_(size), offset_(offset) { } |
| 518 | |
| 519 | bool operator<(const MapItemContainer& other) const { |
| 520 | return offset_ > other.offset_; |
| 521 | } |
| 522 | |
| 523 | uint32_t type_; |
| 524 | uint32_t size_; |
| 525 | uint32_t offset_; |
| 526 | }; |
| 527 | |
| 528 | void DexWriter::WriteMapItem() { |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 529 | dex_ir::Collections& collection = header_->GetCollections(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 530 | std::priority_queue<MapItemContainer> queue; |
| 531 | |
| 532 | // Header and index section. |
| 533 | queue.push(MapItemContainer(DexFile::kDexTypeHeaderItem, 1, 0)); |
| 534 | if (collection.StringIdsSize() != 0) { |
| 535 | queue.push(MapItemContainer(DexFile::kDexTypeStringIdItem, collection.StringIdsSize(), |
| 536 | collection.StringIdsOffset())); |
| 537 | } |
| 538 | if (collection.TypeIdsSize() != 0) { |
| 539 | queue.push(MapItemContainer(DexFile::kDexTypeTypeIdItem, collection.TypeIdsSize(), |
| 540 | collection.TypeIdsOffset())); |
| 541 | } |
| 542 | if (collection.ProtoIdsSize() != 0) { |
| 543 | queue.push(MapItemContainer(DexFile::kDexTypeProtoIdItem, collection.ProtoIdsSize(), |
| 544 | collection.ProtoIdsOffset())); |
| 545 | } |
| 546 | if (collection.FieldIdsSize() != 0) { |
| 547 | queue.push(MapItemContainer(DexFile::kDexTypeFieldIdItem, collection.FieldIdsSize(), |
| 548 | collection.FieldIdsOffset())); |
| 549 | } |
| 550 | if (collection.MethodIdsSize() != 0) { |
| 551 | queue.push(MapItemContainer(DexFile::kDexTypeMethodIdItem, collection.MethodIdsSize(), |
| 552 | collection.MethodIdsOffset())); |
| 553 | } |
| 554 | if (collection.ClassDefsSize() != 0) { |
| 555 | queue.push(MapItemContainer(DexFile::kDexTypeClassDefItem, collection.ClassDefsSize(), |
| 556 | collection.ClassDefsOffset())); |
| 557 | } |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame^] | 558 | if (collection.CallSiteIdsSize() != 0) { |
| 559 | queue.push(MapItemContainer(DexFile::kDexTypeCallSiteIdItem, collection.CallSiteIdsSize(), |
| 560 | collection.CallSiteIdsOffset())); |
| 561 | } |
| 562 | if (collection.MethodHandleItemsSize() != 0) { |
| 563 | queue.push(MapItemContainer(DexFile::kDexTypeMethodHandleItem, |
| 564 | collection.MethodHandleItemsSize(), collection.MethodHandleItemsOffset())); |
| 565 | } |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 566 | |
| 567 | // Data section. |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 568 | queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset())); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 569 | if (collection.TypeListsSize() != 0) { |
| 570 | queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(), |
| 571 | collection.TypeListsOffset())); |
| 572 | } |
| 573 | if (collection.AnnotationSetRefListsSize() != 0) { |
| 574 | queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetRefList, |
| 575 | collection.AnnotationSetRefListsSize(), collection.AnnotationSetRefListsOffset())); |
| 576 | } |
| 577 | if (collection.AnnotationSetItemsSize() != 0) { |
| 578 | queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetItem, |
| 579 | collection.AnnotationSetItemsSize(), collection.AnnotationSetItemsOffset())); |
| 580 | } |
| 581 | if (collection.ClassDatasSize() != 0) { |
| 582 | queue.push(MapItemContainer(DexFile::kDexTypeClassDataItem, collection.ClassDatasSize(), |
| 583 | collection.ClassDatasOffset())); |
| 584 | } |
| 585 | if (collection.CodeItemsSize() != 0) { |
| 586 | queue.push(MapItemContainer(DexFile::kDexTypeCodeItem, collection.CodeItemsSize(), |
| 587 | collection.CodeItemsOffset())); |
| 588 | } |
| 589 | if (collection.StringDatasSize() != 0) { |
| 590 | queue.push(MapItemContainer(DexFile::kDexTypeStringDataItem, collection.StringDatasSize(), |
| 591 | collection.StringDatasOffset())); |
| 592 | } |
| 593 | if (collection.DebugInfoItemsSize() != 0) { |
| 594 | queue.push(MapItemContainer(DexFile::kDexTypeDebugInfoItem, collection.DebugInfoItemsSize(), |
| 595 | collection.DebugInfoItemsOffset())); |
| 596 | } |
| 597 | if (collection.AnnotationItemsSize() != 0) { |
| 598 | queue.push(MapItemContainer(DexFile::kDexTypeAnnotationItem, collection.AnnotationItemsSize(), |
| 599 | collection.AnnotationItemsOffset())); |
| 600 | } |
| 601 | if (collection.EncodedArrayItemsSize() != 0) { |
| 602 | queue.push(MapItemContainer(DexFile::kDexTypeEncodedArrayItem, |
| 603 | collection.EncodedArrayItemsSize(), collection.EncodedArrayItemsOffset())); |
| 604 | } |
| 605 | if (collection.AnnotationsDirectoryItemsSize() != 0) { |
| 606 | queue.push(MapItemContainer(DexFile::kDexTypeAnnotationsDirectoryItem, |
| 607 | collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset())); |
| 608 | } |
| 609 | |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 610 | uint32_t offset = collection.MapListOffset(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 611 | uint16_t uint16_buffer[2]; |
| 612 | uint32_t uint32_buffer[2]; |
| 613 | uint16_buffer[1] = 0; |
| 614 | uint32_buffer[0] = queue.size(); |
| 615 | offset += Write(uint32_buffer, sizeof(uint32_t), offset); |
| 616 | while (!queue.empty()) { |
| 617 | const MapItemContainer& map_item = queue.top(); |
| 618 | uint16_buffer[0] = map_item.type_; |
| 619 | uint32_buffer[0] = map_item.size_; |
| 620 | uint32_buffer[1] = map_item.offset_; |
| 621 | offset += Write(uint16_buffer, 2 * sizeof(uint16_t), offset); |
| 622 | offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset); |
| 623 | queue.pop(); |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | void DexWriter::WriteHeader() { |
| 628 | uint32_t buffer[20]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 629 | dex_ir::Collections& collections = header_->GetCollections(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 630 | size_t offset = 0; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 631 | offset += Write(header_->Magic(), 8 * sizeof(uint8_t), offset); |
| 632 | buffer[0] = header_->Checksum(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 633 | offset += Write(buffer, sizeof(uint32_t), offset); |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 634 | offset += Write(header_->Signature(), 20 * sizeof(uint8_t), offset); |
| 635 | uint32_t file_size = header_->FileSize(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 636 | buffer[0] = file_size; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 637 | buffer[1] = header_->GetSize(); |
| 638 | buffer[2] = header_->EndianTag(); |
| 639 | buffer[3] = header_->LinkSize(); |
| 640 | buffer[4] = header_->LinkOffset(); |
| 641 | buffer[5] = collections.MapListOffset(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 642 | buffer[6] = collections.StringIdsSize(); |
| 643 | buffer[7] = collections.StringIdsOffset(); |
| 644 | buffer[8] = collections.TypeIdsSize(); |
| 645 | buffer[9] = collections.TypeIdsOffset(); |
| 646 | buffer[10] = collections.ProtoIdsSize(); |
| 647 | buffer[11] = collections.ProtoIdsOffset(); |
| 648 | buffer[12] = collections.FieldIdsSize(); |
| 649 | buffer[13] = collections.FieldIdsOffset(); |
| 650 | buffer[14] = collections.MethodIdsSize(); |
| 651 | buffer[15] = collections.MethodIdsOffset(); |
| 652 | uint32_t class_defs_size = collections.ClassDefsSize(); |
| 653 | uint32_t class_defs_off = collections.ClassDefsOffset(); |
| 654 | buffer[16] = class_defs_size; |
| 655 | buffer[17] = class_defs_off; |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame^] | 656 | buffer[18] = header_->DataSize(); |
| 657 | buffer[19] = header_->DataOffset(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 658 | Write(buffer, 20 * sizeof(uint32_t), offset); |
| 659 | } |
| 660 | |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 661 | void DexWriter::WriteMemMap() { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 662 | WriteStrings(); |
| 663 | WriteTypes(); |
| 664 | WriteTypeLists(); |
| 665 | WriteProtos(); |
| 666 | WriteFields(); |
| 667 | WriteMethods(); |
| 668 | WriteEncodedArrays(); |
| 669 | WriteAnnotations(); |
| 670 | WriteAnnotationSets(); |
| 671 | WriteAnnotationSetRefs(); |
| 672 | WriteAnnotationsDirectories(); |
| 673 | WriteDebugInfoItems(); |
| 674 | WriteCodeItems(); |
| 675 | WriteClasses(); |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame^] | 676 | WriteCallSites(); |
| 677 | WriteMethodHandles(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 678 | WriteMapItem(); |
| 679 | WriteHeader(); |
| 680 | } |
| 681 | |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 682 | void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map) { |
| 683 | DexWriter dex_writer(header, mem_map); |
| 684 | dex_writer.WriteMemMap(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 685 | } |
| 686 | |
| 687 | } // namespace art |