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) { |
| 107 | return dex_file_->PwriteFully(buffer, length, offset) ? length : 0; |
| 108 | } |
| 109 | |
| 110 | size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) { |
| 111 | uint8_t buffer[8]; |
| 112 | EncodeSignedLeb128(buffer, value); |
| 113 | return Write(buffer, SignedLeb128Size(value), offset); |
| 114 | } |
| 115 | |
| 116 | size_t DexWriter::WriteUleb128(uint32_t value, size_t offset) { |
| 117 | uint8_t buffer[8]; |
| 118 | EncodeUnsignedLeb128(buffer, value); |
| 119 | return Write(buffer, UnsignedLeb128Size(value), offset); |
| 120 | } |
| 121 | |
| 122 | size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) { |
| 123 | size_t original_offset = offset; |
| 124 | size_t start = 0; |
| 125 | size_t length; |
| 126 | uint8_t buffer[8]; |
| 127 | int8_t type = encoded_value->Type(); |
| 128 | switch (type) { |
| 129 | case DexFile::kDexAnnotationByte: |
| 130 | length = EncodeIntValue(encoded_value->GetByte(), buffer); |
| 131 | break; |
| 132 | case DexFile::kDexAnnotationShort: |
| 133 | length = EncodeIntValue(encoded_value->GetShort(), buffer); |
| 134 | break; |
| 135 | case DexFile::kDexAnnotationChar: |
| 136 | length = EncodeUIntValue(encoded_value->GetChar(), buffer); |
| 137 | break; |
| 138 | case DexFile::kDexAnnotationInt: |
| 139 | length = EncodeIntValue(encoded_value->GetInt(), buffer); |
| 140 | break; |
| 141 | case DexFile::kDexAnnotationLong: |
| 142 | length = EncodeLongValue(encoded_value->GetLong(), buffer); |
| 143 | break; |
| 144 | case DexFile::kDexAnnotationFloat: |
| 145 | length = EncodeFloatValue(encoded_value->GetFloat(), buffer); |
| 146 | start = 4 - length; |
| 147 | break; |
| 148 | case DexFile::kDexAnnotationDouble: |
| 149 | length = EncodeDoubleValue(encoded_value->GetDouble(), buffer); |
| 150 | start = 8 - length; |
| 151 | break; |
| 152 | case DexFile::kDexAnnotationString: |
| 153 | length = EncodeUIntValue(encoded_value->GetStringId()->GetIndex(), buffer); |
| 154 | break; |
| 155 | case DexFile::kDexAnnotationType: |
| 156 | length = EncodeUIntValue(encoded_value->GetTypeId()->GetIndex(), buffer); |
| 157 | break; |
| 158 | case DexFile::kDexAnnotationField: |
| 159 | case DexFile::kDexAnnotationEnum: |
| 160 | length = EncodeUIntValue(encoded_value->GetFieldId()->GetIndex(), buffer); |
| 161 | break; |
| 162 | case DexFile::kDexAnnotationMethod: |
| 163 | length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer); |
| 164 | break; |
| 165 | case DexFile::kDexAnnotationArray: |
| 166 | offset += WriteEncodedValueHeader(type, 0, offset); |
| 167 | offset += WriteEncodedArray(encoded_value->GetEncodedArray()->GetEncodedValues(), offset); |
| 168 | return offset - original_offset; |
| 169 | case DexFile::kDexAnnotationAnnotation: |
| 170 | offset += WriteEncodedValueHeader(type, 0, offset); |
| 171 | offset += WriteEncodedAnnotation(encoded_value->GetEncodedAnnotation(), offset); |
| 172 | return offset - original_offset; |
| 173 | case DexFile::kDexAnnotationNull: |
| 174 | return WriteEncodedValueHeader(type, 0, offset); |
| 175 | case DexFile::kDexAnnotationBoolean: |
| 176 | return WriteEncodedValueHeader(type, encoded_value->GetBoolean() ? 1 : 0, offset); |
| 177 | default: |
| 178 | return 0; |
| 179 | } |
| 180 | offset += WriteEncodedValueHeader(type, length - 1, offset); |
| 181 | offset += Write(buffer + start, length, offset); |
| 182 | return offset - original_offset; |
| 183 | } |
| 184 | |
| 185 | size_t DexWriter::WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) { |
| 186 | uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) }; |
| 187 | return Write(buffer, sizeof(uint8_t), offset); |
| 188 | } |
| 189 | |
| 190 | size_t DexWriter::WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) { |
| 191 | size_t original_offset = offset; |
| 192 | offset += WriteUleb128(values->size(), offset); |
| 193 | for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) { |
| 194 | offset += WriteEncodedValue(value.get(), offset); |
| 195 | } |
| 196 | return offset - original_offset; |
| 197 | } |
| 198 | |
| 199 | size_t DexWriter::WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) { |
| 200 | size_t original_offset = offset; |
| 201 | offset += WriteUleb128(annotation->GetType()->GetIndex(), offset); |
| 202 | offset += WriteUleb128(annotation->GetAnnotationElements()->size(), offset); |
| 203 | for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element : |
| 204 | *annotation->GetAnnotationElements()) { |
| 205 | offset += WriteUleb128(annotation_element->GetName()->GetIndex(), offset); |
| 206 | offset += WriteEncodedValue(annotation_element->GetValue(), offset); |
| 207 | } |
| 208 | return offset - original_offset; |
| 209 | } |
| 210 | |
| 211 | size_t DexWriter::WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) { |
| 212 | size_t original_offset = offset; |
| 213 | uint32_t prev_index = 0; |
| 214 | for (std::unique_ptr<dex_ir::FieldItem>& field : *fields) { |
| 215 | uint32_t index = field->GetFieldId()->GetIndex(); |
| 216 | offset += WriteUleb128(index - prev_index, offset); |
| 217 | offset += WriteUleb128(field->GetAccessFlags(), offset); |
| 218 | prev_index = index; |
| 219 | } |
| 220 | return offset - original_offset; |
| 221 | } |
| 222 | |
| 223 | size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) { |
| 224 | size_t original_offset = offset; |
| 225 | uint32_t prev_index = 0; |
| 226 | for (std::unique_ptr<dex_ir::MethodItem>& method : *methods) { |
| 227 | uint32_t index = method->GetMethodId()->GetIndex(); |
| 228 | uint32_t code_off = method->GetCodeItem() == nullptr ? 0 : method->GetCodeItem()->GetOffset(); |
| 229 | offset += WriteUleb128(index - prev_index, offset); |
| 230 | offset += WriteUleb128(method->GetAccessFlags(), offset); |
| 231 | offset += WriteUleb128(code_off, offset); |
| 232 | prev_index = index; |
| 233 | } |
| 234 | return offset - original_offset; |
| 235 | } |
| 236 | |
| 237 | void DexWriter::WriteStrings() { |
| 238 | uint32_t string_data_off[1]; |
| 239 | for (std::unique_ptr<dex_ir::StringId>& string_id : header_.GetCollections().StringIds()) { |
| 240 | string_data_off[0] = string_id->DataItem()->GetOffset(); |
| 241 | Write(string_data_off, string_id->GetSize(), string_id->GetOffset()); |
| 242 | } |
| 243 | |
| 244 | for (std::unique_ptr<dex_ir::StringData>& string_data : header_.GetCollections().StringDatas()) { |
| 245 | uint32_t offset = string_data->GetOffset(); |
| 246 | offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset); |
| 247 | Write(string_data->Data(), strlen(string_data->Data()), offset); |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | void DexWriter::WriteTypes() { |
| 252 | uint32_t descriptor_idx[1]; |
| 253 | for (std::unique_ptr<dex_ir::TypeId>& type_id : header_.GetCollections().TypeIds()) { |
| 254 | descriptor_idx[0] = type_id->GetStringId()->GetIndex(); |
| 255 | Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset()); |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | void DexWriter::WriteTypeLists() { |
| 260 | uint32_t size[1]; |
| 261 | uint16_t list[1]; |
| 262 | for (std::unique_ptr<dex_ir::TypeList>& type_list : header_.GetCollections().TypeLists()) { |
| 263 | size[0] = type_list->GetTypeList()->size(); |
| 264 | uint32_t offset = type_list->GetOffset(); |
| 265 | offset += Write(size, sizeof(uint32_t), offset); |
| 266 | for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) { |
| 267 | list[0] = type_id->GetIndex(); |
| 268 | offset += Write(list, sizeof(uint16_t), offset); |
| 269 | } |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | void DexWriter::WriteProtos() { |
| 274 | uint32_t buffer[3]; |
| 275 | for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_.GetCollections().ProtoIds()) { |
| 276 | buffer[0] = proto_id->Shorty()->GetIndex(); |
| 277 | buffer[1] = proto_id->ReturnType()->GetIndex(); |
| 278 | buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset(); |
| 279 | Write(buffer, proto_id->GetSize(), proto_id->GetOffset()); |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | void DexWriter::WriteFields() { |
| 284 | uint16_t buffer[4]; |
| 285 | for (std::unique_ptr<dex_ir::FieldId>& field_id : header_.GetCollections().FieldIds()) { |
| 286 | buffer[0] = field_id->Class()->GetIndex(); |
| 287 | buffer[1] = field_id->Type()->GetIndex(); |
| 288 | buffer[2] = field_id->Name()->GetIndex(); |
| 289 | buffer[3] = field_id->Name()->GetIndex() >> 16; |
| 290 | Write(buffer, field_id->GetSize(), field_id->GetOffset()); |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | void DexWriter::WriteMethods() { |
| 295 | uint16_t buffer[4]; |
| 296 | for (std::unique_ptr<dex_ir::MethodId>& method_id : header_.GetCollections().MethodIds()) { |
| 297 | buffer[0] = method_id->Class()->GetIndex(); |
| 298 | buffer[1] = method_id->Proto()->GetIndex(); |
| 299 | buffer[2] = method_id->Name()->GetIndex(); |
| 300 | buffer[3] = method_id->Name()->GetIndex() >> 16; |
| 301 | Write(buffer, method_id->GetSize(), method_id->GetOffset()); |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | void DexWriter::WriteEncodedArrays() { |
| 306 | for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array : |
| 307 | header_.GetCollections().EncodedArrayItems()) { |
| 308 | WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset()); |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | void DexWriter::WriteAnnotations() { |
| 313 | uint8_t visibility[1]; |
| 314 | for (std::unique_ptr<dex_ir::AnnotationItem>& annotation : |
| 315 | header_.GetCollections().AnnotationItems()) { |
| 316 | visibility[0] = annotation->GetVisibility(); |
| 317 | size_t offset = annotation->GetOffset(); |
| 318 | offset += Write(visibility, sizeof(uint8_t), offset); |
| 319 | WriteEncodedAnnotation(annotation->GetAnnotation(), offset); |
| 320 | } |
| 321 | } |
| 322 | |
| 323 | void DexWriter::WriteAnnotationSets() { |
| 324 | uint32_t size[1]; |
| 325 | uint32_t annotation_off[1]; |
| 326 | for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set : |
| 327 | header_.GetCollections().AnnotationSetItems()) { |
| 328 | size[0] = annotation_set->GetItems()->size(); |
| 329 | size_t offset = annotation_set->GetOffset(); |
| 330 | offset += Write(size, sizeof(uint32_t), offset); |
| 331 | for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) { |
| 332 | annotation_off[0] = annotation->GetOffset(); |
| 333 | offset += Write(annotation_off, sizeof(uint32_t), offset); |
| 334 | } |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | void DexWriter::WriteAnnotationSetRefs() { |
| 339 | uint32_t size[1]; |
| 340 | uint32_t annotations_off[1]; |
| 341 | for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref : |
| 342 | header_.GetCollections().AnnotationSetRefLists()) { |
| 343 | size[0] = annotation_set_ref->GetItems()->size(); |
| 344 | size_t offset = annotation_set_ref->GetOffset(); |
| 345 | offset += Write(size, sizeof(uint32_t), offset); |
| 346 | for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) { |
| 347 | annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset(); |
| 348 | offset += Write(annotations_off, sizeof(uint32_t), offset); |
| 349 | } |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | void DexWriter::WriteAnnotationsDirectories() { |
| 354 | uint32_t directory_buffer[4]; |
| 355 | uint32_t annotation_buffer[2]; |
| 356 | for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory : |
| 357 | header_.GetCollections().AnnotationsDirectoryItems()) { |
| 358 | directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 : |
| 359 | annotations_directory->GetClassAnnotation()->GetOffset(); |
| 360 | directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 : |
| 361 | annotations_directory->GetFieldAnnotations()->size(); |
| 362 | directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 : |
| 363 | annotations_directory->GetMethodAnnotations()->size(); |
| 364 | directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 : |
| 365 | annotations_directory->GetParameterAnnotations()->size(); |
| 366 | uint32_t offset = annotations_directory->GetOffset(); |
| 367 | offset += Write(directory_buffer, 4 * sizeof(uint32_t), offset); |
| 368 | if (annotations_directory->GetFieldAnnotations() != nullptr) { |
| 369 | for (std::unique_ptr<dex_ir::FieldAnnotation>& field : |
| 370 | *annotations_directory->GetFieldAnnotations()) { |
| 371 | annotation_buffer[0] = field->GetFieldId()->GetIndex(); |
| 372 | annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset(); |
| 373 | offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); |
| 374 | } |
| 375 | } |
| 376 | if (annotations_directory->GetMethodAnnotations() != nullptr) { |
| 377 | for (std::unique_ptr<dex_ir::MethodAnnotation>& method : |
| 378 | *annotations_directory->GetMethodAnnotations()) { |
| 379 | annotation_buffer[0] = method->GetMethodId()->GetIndex(); |
| 380 | annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset(); |
| 381 | offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); |
| 382 | } |
| 383 | } |
| 384 | if (annotations_directory->GetParameterAnnotations() != nullptr) { |
| 385 | for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter : |
| 386 | *annotations_directory->GetParameterAnnotations()) { |
| 387 | annotation_buffer[0] = parameter->GetMethodId()->GetIndex(); |
| 388 | annotation_buffer[1] = parameter->GetAnnotations()->GetOffset(); |
| 389 | offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); |
| 390 | } |
| 391 | } |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | void DexWriter::WriteDebugInfoItems() { |
| 396 | for (std::unique_ptr<dex_ir::DebugInfoItem>& info : header_.GetCollections().DebugInfoItems()) { |
| 397 | Write(info->GetDebugInfo(), info->GetDebugInfoSize(), info->GetOffset()); |
| 398 | } |
| 399 | } |
| 400 | |
| 401 | void DexWriter::WriteCodeItems() { |
| 402 | uint16_t uint16_buffer[4]; |
| 403 | uint32_t uint32_buffer[2]; |
| 404 | for (std::unique_ptr<dex_ir::CodeItem>& code_item : header_.GetCollections().CodeItems()) { |
| 405 | uint16_buffer[0] = code_item->RegistersSize(); |
| 406 | uint16_buffer[1] = code_item->InsSize(); |
| 407 | uint16_buffer[2] = code_item->OutsSize(); |
| 408 | uint16_buffer[3] = code_item->TriesSize(); |
| 409 | uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 : code_item->DebugInfo()->GetOffset(); |
| 410 | uint32_buffer[1] = code_item->InsnsSize(); |
| 411 | size_t offset = code_item->GetOffset(); |
| 412 | offset += Write(uint16_buffer, 4 * sizeof(uint16_t), offset); |
| 413 | offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset); |
| 414 | offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset); |
| 415 | if (code_item->TriesSize() != 0) { |
| 416 | if (code_item->InsnsSize() % 2 != 0) { |
| 417 | uint16_t padding[1] = { 0 }; |
| 418 | offset += Write(padding, sizeof(uint16_t), offset); |
| 419 | } |
| 420 | uint32_t start_addr[1]; |
| 421 | uint16_t insn_count_and_handler_off[2]; |
| 422 | for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) { |
| 423 | start_addr[0] = try_item->StartAddr(); |
| 424 | insn_count_and_handler_off[0] = try_item->InsnCount(); |
| 425 | insn_count_and_handler_off[1] = try_item->GetHandlers()->GetListOffset(); |
| 426 | offset += Write(start_addr, sizeof(uint32_t), offset); |
| 427 | offset += Write(insn_count_and_handler_off, 2 * sizeof(uint16_t), offset); |
| 428 | } |
| 429 | // Leave offset pointing to the end of the try items. |
| 430 | WriteUleb128(code_item->Handlers()->size(), offset); |
| 431 | for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) { |
| 432 | size_t list_offset = offset + handlers->GetListOffset(); |
| 433 | uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 : |
| 434 | handlers->GetHandlers()->size(); |
| 435 | list_offset += WriteSleb128(size, list_offset); |
| 436 | for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) { |
| 437 | if (handler->GetTypeId() != nullptr) { |
| 438 | list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset); |
| 439 | } |
| 440 | list_offset += WriteUleb128(handler->GetAddress(), list_offset); |
| 441 | } |
| 442 | } |
| 443 | } |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | void DexWriter::WriteClasses() { |
| 448 | uint32_t class_def_buffer[8]; |
| 449 | for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_.GetCollections().ClassDefs()) { |
| 450 | class_def_buffer[0] = class_def->ClassType()->GetIndex(); |
| 451 | class_def_buffer[1] = class_def->GetAccessFlags(); |
| 452 | class_def_buffer[2] = class_def->Superclass() == nullptr ? DexFile::kDexNoIndex : |
| 453 | class_def->Superclass()->GetIndex(); |
| 454 | class_def_buffer[3] = class_def->InterfacesOffset(); |
| 455 | class_def_buffer[4] = class_def->SourceFile() == nullptr ? DexFile::kDexNoIndex : |
| 456 | class_def->SourceFile()->GetIndex(); |
| 457 | class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 : |
| 458 | class_def->Annotations()->GetOffset(); |
| 459 | class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 : |
| 460 | class_def->GetClassData()->GetOffset(); |
| 461 | class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 : |
| 462 | class_def->StaticValues()->GetOffset(); |
| 463 | size_t offset = class_def->GetOffset(); |
| 464 | Write(class_def_buffer, class_def->GetSize(), offset); |
| 465 | } |
| 466 | |
| 467 | for (std::unique_ptr<dex_ir::ClassData>& class_data : header_.GetCollections().ClassDatas()) { |
| 468 | size_t offset = class_data->GetOffset(); |
| 469 | offset += WriteUleb128(class_data->StaticFields()->size(), offset); |
| 470 | offset += WriteUleb128(class_data->InstanceFields()->size(), offset); |
| 471 | offset += WriteUleb128(class_data->DirectMethods()->size(), offset); |
| 472 | offset += WriteUleb128(class_data->VirtualMethods()->size(), offset); |
| 473 | offset += WriteEncodedFields(class_data->StaticFields(), offset); |
| 474 | offset += WriteEncodedFields(class_data->InstanceFields(), offset); |
| 475 | offset += WriteEncodedMethods(class_data->DirectMethods(), offset); |
| 476 | offset += WriteEncodedMethods(class_data->VirtualMethods(), offset); |
| 477 | } |
| 478 | } |
| 479 | |
| 480 | struct MapItemContainer { |
| 481 | MapItemContainer(uint32_t type, uint32_t size, uint32_t offset) |
| 482 | : type_(type), size_(size), offset_(offset) { } |
| 483 | |
| 484 | bool operator<(const MapItemContainer& other) const { |
| 485 | return offset_ > other.offset_; |
| 486 | } |
| 487 | |
| 488 | uint32_t type_; |
| 489 | uint32_t size_; |
| 490 | uint32_t offset_; |
| 491 | }; |
| 492 | |
| 493 | void DexWriter::WriteMapItem() { |
| 494 | dex_ir::Collections& collection = header_.GetCollections(); |
| 495 | std::priority_queue<MapItemContainer> queue; |
| 496 | |
| 497 | // Header and index section. |
| 498 | queue.push(MapItemContainer(DexFile::kDexTypeHeaderItem, 1, 0)); |
| 499 | if (collection.StringIdsSize() != 0) { |
| 500 | queue.push(MapItemContainer(DexFile::kDexTypeStringIdItem, collection.StringIdsSize(), |
| 501 | collection.StringIdsOffset())); |
| 502 | } |
| 503 | if (collection.TypeIdsSize() != 0) { |
| 504 | queue.push(MapItemContainer(DexFile::kDexTypeTypeIdItem, collection.TypeIdsSize(), |
| 505 | collection.TypeIdsOffset())); |
| 506 | } |
| 507 | if (collection.ProtoIdsSize() != 0) { |
| 508 | queue.push(MapItemContainer(DexFile::kDexTypeProtoIdItem, collection.ProtoIdsSize(), |
| 509 | collection.ProtoIdsOffset())); |
| 510 | } |
| 511 | if (collection.FieldIdsSize() != 0) { |
| 512 | queue.push(MapItemContainer(DexFile::kDexTypeFieldIdItem, collection.FieldIdsSize(), |
| 513 | collection.FieldIdsOffset())); |
| 514 | } |
| 515 | if (collection.MethodIdsSize() != 0) { |
| 516 | queue.push(MapItemContainer(DexFile::kDexTypeMethodIdItem, collection.MethodIdsSize(), |
| 517 | collection.MethodIdsOffset())); |
| 518 | } |
| 519 | if (collection.ClassDefsSize() != 0) { |
| 520 | queue.push(MapItemContainer(DexFile::kDexTypeClassDefItem, collection.ClassDefsSize(), |
| 521 | collection.ClassDefsOffset())); |
| 522 | } |
| 523 | |
| 524 | // Data section. |
| 525 | queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapItemOffset())); |
| 526 | if (collection.TypeListsSize() != 0) { |
| 527 | queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(), |
| 528 | collection.TypeListsOffset())); |
| 529 | } |
| 530 | if (collection.AnnotationSetRefListsSize() != 0) { |
| 531 | queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetRefList, |
| 532 | collection.AnnotationSetRefListsSize(), collection.AnnotationSetRefListsOffset())); |
| 533 | } |
| 534 | if (collection.AnnotationSetItemsSize() != 0) { |
| 535 | queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetItem, |
| 536 | collection.AnnotationSetItemsSize(), collection.AnnotationSetItemsOffset())); |
| 537 | } |
| 538 | if (collection.ClassDatasSize() != 0) { |
| 539 | queue.push(MapItemContainer(DexFile::kDexTypeClassDataItem, collection.ClassDatasSize(), |
| 540 | collection.ClassDatasOffset())); |
| 541 | } |
| 542 | if (collection.CodeItemsSize() != 0) { |
| 543 | queue.push(MapItemContainer(DexFile::kDexTypeCodeItem, collection.CodeItemsSize(), |
| 544 | collection.CodeItemsOffset())); |
| 545 | } |
| 546 | if (collection.StringDatasSize() != 0) { |
| 547 | queue.push(MapItemContainer(DexFile::kDexTypeStringDataItem, collection.StringDatasSize(), |
| 548 | collection.StringDatasOffset())); |
| 549 | } |
| 550 | if (collection.DebugInfoItemsSize() != 0) { |
| 551 | queue.push(MapItemContainer(DexFile::kDexTypeDebugInfoItem, collection.DebugInfoItemsSize(), |
| 552 | collection.DebugInfoItemsOffset())); |
| 553 | } |
| 554 | if (collection.AnnotationItemsSize() != 0) { |
| 555 | queue.push(MapItemContainer(DexFile::kDexTypeAnnotationItem, collection.AnnotationItemsSize(), |
| 556 | collection.AnnotationItemsOffset())); |
| 557 | } |
| 558 | if (collection.EncodedArrayItemsSize() != 0) { |
| 559 | queue.push(MapItemContainer(DexFile::kDexTypeEncodedArrayItem, |
| 560 | collection.EncodedArrayItemsSize(), collection.EncodedArrayItemsOffset())); |
| 561 | } |
| 562 | if (collection.AnnotationsDirectoryItemsSize() != 0) { |
| 563 | queue.push(MapItemContainer(DexFile::kDexTypeAnnotationsDirectoryItem, |
| 564 | collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset())); |
| 565 | } |
| 566 | |
| 567 | uint32_t offset = collection.MapItemOffset(); |
| 568 | uint16_t uint16_buffer[2]; |
| 569 | uint32_t uint32_buffer[2]; |
| 570 | uint16_buffer[1] = 0; |
| 571 | uint32_buffer[0] = queue.size(); |
| 572 | offset += Write(uint32_buffer, sizeof(uint32_t), offset); |
| 573 | while (!queue.empty()) { |
| 574 | const MapItemContainer& map_item = queue.top(); |
| 575 | uint16_buffer[0] = map_item.type_; |
| 576 | uint32_buffer[0] = map_item.size_; |
| 577 | uint32_buffer[1] = map_item.offset_; |
| 578 | offset += Write(uint16_buffer, 2 * sizeof(uint16_t), offset); |
| 579 | offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset); |
| 580 | queue.pop(); |
| 581 | } |
| 582 | } |
| 583 | |
| 584 | void DexWriter::WriteHeader() { |
| 585 | uint32_t buffer[20]; |
| 586 | dex_ir::Collections& collections = header_.GetCollections(); |
| 587 | size_t offset = 0; |
| 588 | offset += Write(header_.Magic(), 8 * sizeof(uint8_t), offset); |
| 589 | buffer[0] = header_.Checksum(); |
| 590 | offset += Write(buffer, sizeof(uint32_t), offset); |
| 591 | offset += Write(header_.Signature(), 20 * sizeof(uint8_t), offset); |
| 592 | uint32_t file_size = header_.FileSize(); |
| 593 | buffer[0] = file_size; |
| 594 | buffer[1] = header_.GetSize(); |
| 595 | buffer[2] = header_.EndianTag(); |
| 596 | buffer[3] = header_.LinkSize(); |
| 597 | buffer[4] = header_.LinkOffset(); |
| 598 | buffer[5] = collections.MapItemOffset(); |
| 599 | buffer[6] = collections.StringIdsSize(); |
| 600 | buffer[7] = collections.StringIdsOffset(); |
| 601 | buffer[8] = collections.TypeIdsSize(); |
| 602 | buffer[9] = collections.TypeIdsOffset(); |
| 603 | buffer[10] = collections.ProtoIdsSize(); |
| 604 | buffer[11] = collections.ProtoIdsOffset(); |
| 605 | buffer[12] = collections.FieldIdsSize(); |
| 606 | buffer[13] = collections.FieldIdsOffset(); |
| 607 | buffer[14] = collections.MethodIdsSize(); |
| 608 | buffer[15] = collections.MethodIdsOffset(); |
| 609 | uint32_t class_defs_size = collections.ClassDefsSize(); |
| 610 | uint32_t class_defs_off = collections.ClassDefsOffset(); |
| 611 | buffer[16] = class_defs_size; |
| 612 | buffer[17] = class_defs_off; |
| 613 | uint32_t data_off = class_defs_off + class_defs_size * dex_ir::ClassDef::ItemSize(); |
| 614 | uint32_t data_size = file_size - data_off; |
| 615 | buffer[18] = data_size; |
| 616 | buffer[19] = data_off; |
| 617 | Write(buffer, 20 * sizeof(uint32_t), offset); |
| 618 | } |
| 619 | |
| 620 | void DexWriter::WriteFile() { |
| 621 | if (dex_file_.get() == nullptr) { |
| 622 | fprintf(stderr, "Can't open output dex file\n"); |
| 623 | return; |
| 624 | } |
| 625 | |
| 626 | WriteStrings(); |
| 627 | WriteTypes(); |
| 628 | WriteTypeLists(); |
| 629 | WriteProtos(); |
| 630 | WriteFields(); |
| 631 | WriteMethods(); |
| 632 | WriteEncodedArrays(); |
| 633 | WriteAnnotations(); |
| 634 | WriteAnnotationSets(); |
| 635 | WriteAnnotationSetRefs(); |
| 636 | WriteAnnotationsDirectories(); |
| 637 | WriteDebugInfoItems(); |
| 638 | WriteCodeItems(); |
| 639 | WriteClasses(); |
| 640 | WriteMapItem(); |
| 641 | WriteHeader(); |
| 642 | } |
| 643 | |
| 644 | void DexWriter::OutputDexFile(dex_ir::Header& header, const char* file_name) { |
| 645 | (new DexWriter(header, file_name))->WriteFile(); |
| 646 | } |
| 647 | |
| 648 | } // namespace art |