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. |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 15 | */ |
| 16 | |
Andreas Gampe | e2abbc6 | 2017-09-15 11:59:26 -0700 | [diff] [blame] | 17 | #include "dex_writer.h" |
| 18 | |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 19 | #include <stdint.h> |
| 20 | |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 21 | #include <vector> |
| 22 | |
Mathieu Chartier | 603ccab | 2017-10-20 14:34:28 -0700 | [diff] [blame] | 23 | #include "cdex/compact_dex_file.h" |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 24 | #include "compact_dex_writer.h" |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 25 | #include "dex_file_layout.h" |
Andreas Gampe | e2abbc6 | 2017-09-15 11:59:26 -0700 | [diff] [blame] | 26 | #include "dex_file_types.h" |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 27 | #include "dexlayout.h" |
Mathieu Chartier | 603ccab | 2017-10-20 14:34:28 -0700 | [diff] [blame] | 28 | #include "standard_dex_file.h" |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 29 | #include "utf.h" |
| 30 | |
| 31 | namespace art { |
| 32 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 33 | static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2; |
| 34 | static constexpr uint32_t kDexSectionWordAlignment = 4; |
| 35 | |
| 36 | static constexpr uint32_t SectionAlignment(DexFile::MapItemType type) { |
| 37 | switch (type) { |
| 38 | case DexFile::kDexTypeClassDataItem: |
| 39 | case DexFile::kDexTypeStringDataItem: |
| 40 | case DexFile::kDexTypeDebugInfoItem: |
| 41 | case DexFile::kDexTypeAnnotationItem: |
| 42 | case DexFile::kDexTypeEncodedArrayItem: |
| 43 | return alignof(uint8_t); |
| 44 | |
| 45 | default: |
| 46 | // All other sections are kDexAlignedSection. |
| 47 | return kDexSectionWordAlignment; |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 52 | size_t EncodeIntValue(int32_t value, uint8_t* buffer) { |
| 53 | size_t length = 0; |
| 54 | if (value >= 0) { |
| 55 | while (value > 0x7f) { |
| 56 | buffer[length++] = static_cast<uint8_t>(value); |
| 57 | value >>= 8; |
| 58 | } |
| 59 | } else { |
| 60 | while (value < -0x80) { |
| 61 | buffer[length++] = static_cast<uint8_t>(value); |
| 62 | value >>= 8; |
| 63 | } |
| 64 | } |
| 65 | buffer[length++] = static_cast<uint8_t>(value); |
| 66 | return length; |
| 67 | } |
| 68 | |
| 69 | size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) { |
| 70 | size_t length = 0; |
| 71 | do { |
| 72 | buffer[length++] = static_cast<uint8_t>(value); |
| 73 | value >>= 8; |
| 74 | } while (value != 0); |
| 75 | return length; |
| 76 | } |
| 77 | |
| 78 | size_t EncodeLongValue(int64_t value, uint8_t* buffer) { |
| 79 | size_t length = 0; |
| 80 | if (value >= 0) { |
| 81 | while (value > 0x7f) { |
| 82 | buffer[length++] = static_cast<uint8_t>(value); |
| 83 | value >>= 8; |
| 84 | } |
| 85 | } else { |
| 86 | while (value < -0x80) { |
| 87 | buffer[length++] = static_cast<uint8_t>(value); |
| 88 | value >>= 8; |
| 89 | } |
| 90 | } |
| 91 | buffer[length++] = static_cast<uint8_t>(value); |
| 92 | return length; |
| 93 | } |
| 94 | |
| 95 | union FloatUnion { |
| 96 | float f_; |
| 97 | uint32_t i_; |
| 98 | }; |
| 99 | |
| 100 | size_t EncodeFloatValue(float value, uint8_t* buffer) { |
| 101 | FloatUnion float_union; |
| 102 | float_union.f_ = value; |
| 103 | uint32_t int_value = float_union.i_; |
| 104 | size_t index = 3; |
| 105 | do { |
| 106 | buffer[index--] = int_value >> 24; |
| 107 | int_value <<= 8; |
| 108 | } while (int_value != 0); |
| 109 | return 3 - index; |
| 110 | } |
| 111 | |
| 112 | union DoubleUnion { |
| 113 | double d_; |
| 114 | uint64_t l_; |
| 115 | }; |
| 116 | |
| 117 | size_t EncodeDoubleValue(double value, uint8_t* buffer) { |
| 118 | DoubleUnion double_union; |
| 119 | double_union.d_ = value; |
| 120 | uint64_t long_value = double_union.l_; |
| 121 | size_t index = 7; |
| 122 | do { |
| 123 | buffer[index--] = long_value >> 56; |
| 124 | long_value <<= 8; |
| 125 | } while (long_value != 0); |
| 126 | return 7 - index; |
| 127 | } |
| 128 | |
| 129 | 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] | 130 | DCHECK_LE(offset + length, mem_map_->Size()); |
| 131 | memcpy(mem_map_->Begin() + offset, buffer, length); |
| 132 | return length; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) { |
| 136 | uint8_t buffer[8]; |
| 137 | EncodeSignedLeb128(buffer, value); |
| 138 | return Write(buffer, SignedLeb128Size(value), offset); |
| 139 | } |
| 140 | |
| 141 | size_t DexWriter::WriteUleb128(uint32_t value, size_t offset) { |
| 142 | uint8_t buffer[8]; |
| 143 | EncodeUnsignedLeb128(buffer, value); |
| 144 | return Write(buffer, UnsignedLeb128Size(value), offset); |
| 145 | } |
| 146 | |
| 147 | size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) { |
| 148 | size_t original_offset = offset; |
| 149 | size_t start = 0; |
| 150 | size_t length; |
| 151 | uint8_t buffer[8]; |
| 152 | int8_t type = encoded_value->Type(); |
| 153 | switch (type) { |
| 154 | case DexFile::kDexAnnotationByte: |
| 155 | length = EncodeIntValue(encoded_value->GetByte(), buffer); |
| 156 | break; |
| 157 | case DexFile::kDexAnnotationShort: |
| 158 | length = EncodeIntValue(encoded_value->GetShort(), buffer); |
| 159 | break; |
| 160 | case DexFile::kDexAnnotationChar: |
| 161 | length = EncodeUIntValue(encoded_value->GetChar(), buffer); |
| 162 | break; |
| 163 | case DexFile::kDexAnnotationInt: |
| 164 | length = EncodeIntValue(encoded_value->GetInt(), buffer); |
| 165 | break; |
| 166 | case DexFile::kDexAnnotationLong: |
| 167 | length = EncodeLongValue(encoded_value->GetLong(), buffer); |
| 168 | break; |
| 169 | case DexFile::kDexAnnotationFloat: |
| 170 | length = EncodeFloatValue(encoded_value->GetFloat(), buffer); |
| 171 | start = 4 - length; |
| 172 | break; |
| 173 | case DexFile::kDexAnnotationDouble: |
| 174 | length = EncodeDoubleValue(encoded_value->GetDouble(), buffer); |
| 175 | start = 8 - length; |
| 176 | break; |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame] | 177 | case DexFile::kDexAnnotationMethodType: |
| 178 | length = EncodeUIntValue(encoded_value->GetProtoId()->GetIndex(), buffer); |
| 179 | break; |
| 180 | case DexFile::kDexAnnotationMethodHandle: |
| 181 | length = EncodeUIntValue(encoded_value->GetMethodHandle()->GetIndex(), buffer); |
| 182 | break; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 183 | case DexFile::kDexAnnotationString: |
| 184 | length = EncodeUIntValue(encoded_value->GetStringId()->GetIndex(), buffer); |
| 185 | break; |
| 186 | case DexFile::kDexAnnotationType: |
| 187 | length = EncodeUIntValue(encoded_value->GetTypeId()->GetIndex(), buffer); |
| 188 | break; |
| 189 | case DexFile::kDexAnnotationField: |
| 190 | case DexFile::kDexAnnotationEnum: |
| 191 | length = EncodeUIntValue(encoded_value->GetFieldId()->GetIndex(), buffer); |
| 192 | break; |
| 193 | case DexFile::kDexAnnotationMethod: |
| 194 | length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer); |
| 195 | break; |
| 196 | case DexFile::kDexAnnotationArray: |
| 197 | offset += WriteEncodedValueHeader(type, 0, offset); |
| 198 | offset += WriteEncodedArray(encoded_value->GetEncodedArray()->GetEncodedValues(), offset); |
| 199 | return offset - original_offset; |
| 200 | case DexFile::kDexAnnotationAnnotation: |
| 201 | offset += WriteEncodedValueHeader(type, 0, offset); |
| 202 | offset += WriteEncodedAnnotation(encoded_value->GetEncodedAnnotation(), offset); |
| 203 | return offset - original_offset; |
| 204 | case DexFile::kDexAnnotationNull: |
| 205 | return WriteEncodedValueHeader(type, 0, offset); |
| 206 | case DexFile::kDexAnnotationBoolean: |
| 207 | return WriteEncodedValueHeader(type, encoded_value->GetBoolean() ? 1 : 0, offset); |
| 208 | default: |
| 209 | return 0; |
| 210 | } |
| 211 | offset += WriteEncodedValueHeader(type, length - 1, offset); |
| 212 | offset += Write(buffer + start, length, offset); |
| 213 | return offset - original_offset; |
| 214 | } |
| 215 | |
| 216 | size_t DexWriter::WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) { |
| 217 | uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) }; |
| 218 | return Write(buffer, sizeof(uint8_t), offset); |
| 219 | } |
| 220 | |
| 221 | size_t DexWriter::WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) { |
| 222 | size_t original_offset = offset; |
| 223 | offset += WriteUleb128(values->size(), offset); |
| 224 | for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) { |
| 225 | offset += WriteEncodedValue(value.get(), offset); |
| 226 | } |
| 227 | return offset - original_offset; |
| 228 | } |
| 229 | |
| 230 | size_t DexWriter::WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) { |
| 231 | size_t original_offset = offset; |
| 232 | offset += WriteUleb128(annotation->GetType()->GetIndex(), offset); |
| 233 | offset += WriteUleb128(annotation->GetAnnotationElements()->size(), offset); |
| 234 | for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element : |
| 235 | *annotation->GetAnnotationElements()) { |
| 236 | offset += WriteUleb128(annotation_element->GetName()->GetIndex(), offset); |
| 237 | offset += WriteEncodedValue(annotation_element->GetValue(), offset); |
| 238 | } |
| 239 | return offset - original_offset; |
| 240 | } |
| 241 | |
| 242 | size_t DexWriter::WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) { |
| 243 | size_t original_offset = offset; |
| 244 | uint32_t prev_index = 0; |
| 245 | for (std::unique_ptr<dex_ir::FieldItem>& field : *fields) { |
| 246 | uint32_t index = field->GetFieldId()->GetIndex(); |
| 247 | offset += WriteUleb128(index - prev_index, offset); |
| 248 | offset += WriteUleb128(field->GetAccessFlags(), offset); |
| 249 | prev_index = index; |
| 250 | } |
| 251 | return offset - original_offset; |
| 252 | } |
| 253 | |
| 254 | size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) { |
| 255 | size_t original_offset = offset; |
| 256 | uint32_t prev_index = 0; |
| 257 | for (std::unique_ptr<dex_ir::MethodItem>& method : *methods) { |
| 258 | uint32_t index = method->GetMethodId()->GetIndex(); |
| 259 | uint32_t code_off = method->GetCodeItem() == nullptr ? 0 : method->GetCodeItem()->GetOffset(); |
| 260 | offset += WriteUleb128(index - prev_index, offset); |
| 261 | offset += WriteUleb128(method->GetAccessFlags(), offset); |
| 262 | offset += WriteUleb128(code_off, offset); |
| 263 | prev_index = index; |
| 264 | } |
| 265 | return offset - original_offset; |
| 266 | } |
| 267 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 268 | // TODO: Refactor this to remove duplicated boiler plate. One way to do this is adding |
| 269 | // function that takes a CollectionVector<T> and uses overloading. |
| 270 | uint32_t DexWriter::WriteStringIds(uint32_t offset, bool reserve_only) { |
| 271 | const uint32_t start = offset; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 272 | for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 273 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeStringIdItem)); |
| 274 | if (reserve_only) { |
| 275 | offset += string_id->GetSize(); |
| 276 | } else { |
| 277 | uint32_t string_data_off = string_id->DataItem()->GetOffset(); |
| 278 | offset += Write(&string_data_off, string_id->GetSize(), offset); |
| 279 | } |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 280 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 281 | if (compute_offsets_ && start != offset) { |
| 282 | header_->GetCollections().SetStringIdsOffset(start); |
| 283 | } |
| 284 | return offset - start; |
| 285 | } |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 286 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 287 | uint32_t DexWriter::WriteStringDatas(uint32_t offset) { |
| 288 | const uint32_t start = offset; |
| 289 | for (std::unique_ptr<dex_ir::StringData>& string_data : header_->GetCollections().StringDatas()) { |
| 290 | ProcessOffset(&offset, string_data.get()); |
| 291 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeStringDataItem)); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 292 | offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 293 | // Skip null terminator (already zeroed out, no need to write). |
| 294 | offset += Write(string_data->Data(), strlen(string_data->Data()), offset) + 1u; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 295 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 296 | if (compute_offsets_ && start != offset) { |
| 297 | header_->GetCollections().SetStringDatasOffset(start); |
| 298 | } |
| 299 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 300 | } |
| 301 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 302 | uint32_t DexWriter::WriteTypeIds(uint32_t offset) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 303 | uint32_t descriptor_idx[1]; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 304 | const uint32_t start = offset; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 305 | for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 306 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeTypeIdItem)); |
| 307 | ProcessOffset(&offset, type_id.get()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 308 | descriptor_idx[0] = type_id->GetStringId()->GetIndex(); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 309 | offset += Write(descriptor_idx, type_id->GetSize(), offset); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 310 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 311 | if (compute_offsets_ && start != offset) { |
| 312 | header_->GetCollections().SetTypeIdsOffset(start); |
| 313 | } |
| 314 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 315 | } |
| 316 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 317 | uint32_t DexWriter::WriteTypeLists(uint32_t offset) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 318 | uint32_t size[1]; |
| 319 | uint16_t list[1]; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 320 | const uint32_t start = offset; |
| 321 | for (std::unique_ptr<dex_ir::TypeList>& type_list : header_->GetCollections().TypeLists()) { |
| 322 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeTypeList)); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 323 | size[0] = type_list->GetTypeList()->size(); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 324 | ProcessOffset(&offset, type_list.get()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 325 | offset += Write(size, sizeof(uint32_t), offset); |
| 326 | for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) { |
| 327 | list[0] = type_id->GetIndex(); |
| 328 | offset += Write(list, sizeof(uint16_t), offset); |
| 329 | } |
| 330 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 331 | if (compute_offsets_ && start != offset) { |
| 332 | header_->GetCollections().SetTypeListsOffset(start); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 333 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 334 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 335 | } |
| 336 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 337 | uint32_t DexWriter::WriteProtoIds(uint32_t offset, bool reserve_only) { |
| 338 | uint32_t buffer[3]; |
| 339 | const uint32_t start = offset; |
| 340 | for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) { |
| 341 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeProtoIdItem)); |
| 342 | ProcessOffset(&offset, proto_id.get()); |
| 343 | if (reserve_only) { |
| 344 | offset += proto_id->GetSize(); |
| 345 | } else { |
| 346 | buffer[0] = proto_id->Shorty()->GetIndex(); |
| 347 | buffer[1] = proto_id->ReturnType()->GetIndex(); |
| 348 | buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset(); |
| 349 | offset += Write(buffer, proto_id->GetSize(), offset); |
| 350 | } |
| 351 | } |
| 352 | if (compute_offsets_ && start != offset) { |
| 353 | header_->GetCollections().SetProtoIdsOffset(start); |
| 354 | } |
| 355 | return offset - start; |
| 356 | } |
| 357 | |
| 358 | uint32_t DexWriter::WriteFieldIds(uint32_t offset) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 359 | uint16_t buffer[4]; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 360 | const uint32_t start = offset; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 361 | for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 362 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeFieldIdItem)); |
| 363 | ProcessOffset(&offset, field_id.get()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 364 | buffer[0] = field_id->Class()->GetIndex(); |
| 365 | buffer[1] = field_id->Type()->GetIndex(); |
| 366 | buffer[2] = field_id->Name()->GetIndex(); |
| 367 | buffer[3] = field_id->Name()->GetIndex() >> 16; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 368 | offset += Write(buffer, field_id->GetSize(), offset); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 369 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 370 | if (compute_offsets_ && start != offset) { |
| 371 | header_->GetCollections().SetFieldIdsOffset(start); |
| 372 | } |
| 373 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 374 | } |
| 375 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 376 | uint32_t DexWriter::WriteMethodIds(uint32_t offset) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 377 | uint16_t buffer[4]; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 378 | const uint32_t start = offset; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 379 | for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 380 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMethodIdItem)); |
| 381 | ProcessOffset(&offset, method_id.get()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 382 | buffer[0] = method_id->Class()->GetIndex(); |
| 383 | buffer[1] = method_id->Proto()->GetIndex(); |
| 384 | buffer[2] = method_id->Name()->GetIndex(); |
| 385 | buffer[3] = method_id->Name()->GetIndex() >> 16; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 386 | offset += Write(buffer, method_id->GetSize(), offset); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 387 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 388 | if (compute_offsets_ && start != offset) { |
| 389 | header_->GetCollections().SetMethodIdsOffset(start); |
| 390 | } |
| 391 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 392 | } |
| 393 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 394 | uint32_t DexWriter::WriteEncodedArrays(uint32_t offset) { |
| 395 | const uint32_t start = offset; |
| 396 | for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array : |
| 397 | header_->GetCollections().EncodedArrayItems()) { |
| 398 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeEncodedArrayItem)); |
| 399 | ProcessOffset(&offset, encoded_array.get()); |
| 400 | offset += WriteEncodedArray(encoded_array->GetEncodedValues(), offset); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 401 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 402 | if (compute_offsets_ && start != offset) { |
| 403 | header_->GetCollections().SetEncodedArrayItemsOffset(start); |
| 404 | } |
| 405 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 406 | } |
| 407 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 408 | uint32_t DexWriter::WriteAnnotations(uint32_t offset) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 409 | uint8_t visibility[1]; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 410 | const uint32_t start = offset; |
| 411 | for (std::unique_ptr<dex_ir::AnnotationItem>& annotation : |
| 412 | header_->GetCollections().AnnotationItems()) { |
| 413 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationItem)); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 414 | visibility[0] = annotation->GetVisibility(); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 415 | ProcessOffset(&offset, annotation.get()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 416 | offset += Write(visibility, sizeof(uint8_t), offset); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 417 | offset += WriteEncodedAnnotation(annotation->GetAnnotation(), offset); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 418 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 419 | if (compute_offsets_ && start != offset) { |
| 420 | header_->GetCollections().SetAnnotationItemsOffset(start); |
| 421 | } |
| 422 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 423 | } |
| 424 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 425 | uint32_t DexWriter::WriteAnnotationSets(uint32_t offset) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 426 | uint32_t size[1]; |
| 427 | uint32_t annotation_off[1]; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 428 | const uint32_t start = offset; |
| 429 | for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set : |
| 430 | header_->GetCollections().AnnotationSetItems()) { |
| 431 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationSetItem)); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 432 | size[0] = annotation_set->GetItems()->size(); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 433 | ProcessOffset(&offset, annotation_set.get()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 434 | offset += Write(size, sizeof(uint32_t), offset); |
| 435 | for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) { |
| 436 | annotation_off[0] = annotation->GetOffset(); |
| 437 | offset += Write(annotation_off, sizeof(uint32_t), offset); |
| 438 | } |
| 439 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 440 | if (compute_offsets_ && start != offset) { |
| 441 | header_->GetCollections().SetAnnotationSetItemsOffset(start); |
| 442 | } |
| 443 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 444 | } |
| 445 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 446 | uint32_t DexWriter::WriteAnnotationSetRefs(uint32_t offset) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 447 | uint32_t size[1]; |
| 448 | uint32_t annotations_off[1]; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 449 | const uint32_t start = offset; |
| 450 | for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref : |
| 451 | header_->GetCollections().AnnotationSetRefLists()) { |
| 452 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationSetRefList)); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 453 | size[0] = annotation_set_ref->GetItems()->size(); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 454 | ProcessOffset(&offset, annotation_set_ref.get()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 455 | offset += Write(size, sizeof(uint32_t), offset); |
| 456 | for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) { |
| 457 | annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset(); |
| 458 | offset += Write(annotations_off, sizeof(uint32_t), offset); |
| 459 | } |
| 460 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 461 | if (compute_offsets_ && start != offset) { |
| 462 | header_->GetCollections().SetAnnotationSetRefListsOffset(start); |
| 463 | } |
| 464 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 465 | } |
| 466 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 467 | uint32_t DexWriter::WriteAnnotationsDirectories(uint32_t offset) { |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 468 | uint32_t directory_buffer[4]; |
| 469 | uint32_t annotation_buffer[2]; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 470 | const uint32_t start = offset; |
| 471 | for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory : |
| 472 | header_->GetCollections().AnnotationsDirectoryItems()) { |
| 473 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem)); |
| 474 | ProcessOffset(&offset, annotations_directory.get()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 475 | directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 : |
| 476 | annotations_directory->GetClassAnnotation()->GetOffset(); |
| 477 | directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 : |
| 478 | annotations_directory->GetFieldAnnotations()->size(); |
| 479 | directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 : |
| 480 | annotations_directory->GetMethodAnnotations()->size(); |
| 481 | directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 : |
| 482 | annotations_directory->GetParameterAnnotations()->size(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 483 | offset += Write(directory_buffer, 4 * sizeof(uint32_t), offset); |
| 484 | if (annotations_directory->GetFieldAnnotations() != nullptr) { |
| 485 | for (std::unique_ptr<dex_ir::FieldAnnotation>& field : |
| 486 | *annotations_directory->GetFieldAnnotations()) { |
| 487 | annotation_buffer[0] = field->GetFieldId()->GetIndex(); |
| 488 | annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset(); |
| 489 | offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); |
| 490 | } |
| 491 | } |
| 492 | if (annotations_directory->GetMethodAnnotations() != nullptr) { |
| 493 | for (std::unique_ptr<dex_ir::MethodAnnotation>& method : |
| 494 | *annotations_directory->GetMethodAnnotations()) { |
| 495 | annotation_buffer[0] = method->GetMethodId()->GetIndex(); |
| 496 | annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset(); |
| 497 | offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); |
| 498 | } |
| 499 | } |
| 500 | if (annotations_directory->GetParameterAnnotations() != nullptr) { |
| 501 | for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter : |
| 502 | *annotations_directory->GetParameterAnnotations()) { |
| 503 | annotation_buffer[0] = parameter->GetMethodId()->GetIndex(); |
| 504 | annotation_buffer[1] = parameter->GetAnnotations()->GetOffset(); |
| 505 | offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); |
| 506 | } |
| 507 | } |
| 508 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 509 | if (compute_offsets_ && start != offset) { |
| 510 | header_->GetCollections().SetAnnotationsDirectoryItemsOffset(start); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 511 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 512 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 513 | } |
| 514 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 515 | uint32_t DexWriter::WriteDebugInfoItems(uint32_t offset) { |
| 516 | const uint32_t start = offset; |
| 517 | for (std::unique_ptr<dex_ir::DebugInfoItem>& debug_info : |
| 518 | header_->GetCollections().DebugInfoItems()) { |
| 519 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeDebugInfoItem)); |
| 520 | ProcessOffset(&offset, debug_info.get()); |
| 521 | offset += Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), offset); |
| 522 | } |
| 523 | if (compute_offsets_ && start != offset) { |
| 524 | header_->GetCollections().SetDebugInfoItemsOffset(start); |
| 525 | } |
| 526 | return offset - start; |
| 527 | } |
| 528 | |
| 529 | uint32_t DexWriter::WriteCodeItems(uint32_t offset, bool reserve_only) { |
| 530 | DexLayoutSection* code_section = nullptr; |
| 531 | if (!reserve_only && dex_layout_ != nullptr) { |
| 532 | code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>( |
| 533 | DexLayoutSections::SectionType::kSectionTypeCode)]; |
| 534 | } |
| 535 | uint16_t uint16_buffer[4] = {}; |
| 536 | uint32_t uint32_buffer[2] = {}; |
| 537 | uint32_t start = offset; |
| 538 | for (auto& code_item : header_->GetCollections().CodeItems()) { |
| 539 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCodeItem)); |
| 540 | ProcessOffset(&offset, code_item.get()); |
| 541 | if (!reserve_only) { |
| 542 | uint16_buffer[0] = code_item->RegistersSize(); |
| 543 | uint16_buffer[1] = code_item->InsSize(); |
| 544 | uint16_buffer[2] = code_item->OutsSize(); |
| 545 | uint16_buffer[3] = code_item->TriesSize(); |
| 546 | uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 : |
| 547 | code_item->DebugInfo()->GetOffset(); |
| 548 | uint32_buffer[1] = code_item->InsnsSize(); |
| 549 | // Only add the section hotness info once. |
| 550 | if (code_section != nullptr) { |
| 551 | auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get()); |
| 552 | if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) { |
| 553 | code_section->parts_[static_cast<size_t>(it->second)].CombineSection( |
| 554 | code_item->GetOffset(), code_item->GetOffset() + code_item->GetSize()); |
| 555 | } |
| 556 | } |
| 557 | } |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 558 | offset += Write(uint16_buffer, 4 * sizeof(uint16_t), offset); |
| 559 | offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset); |
| 560 | offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset); |
| 561 | if (code_item->TriesSize() != 0) { |
| 562 | if (code_item->InsnsSize() % 2 != 0) { |
| 563 | uint16_t padding[1] = { 0 }; |
| 564 | offset += Write(padding, sizeof(uint16_t), offset); |
| 565 | } |
| 566 | uint32_t start_addr[1]; |
| 567 | uint16_t insn_count_and_handler_off[2]; |
| 568 | for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) { |
| 569 | start_addr[0] = try_item->StartAddr(); |
| 570 | insn_count_and_handler_off[0] = try_item->InsnCount(); |
| 571 | insn_count_and_handler_off[1] = try_item->GetHandlers()->GetListOffset(); |
| 572 | offset += Write(start_addr, sizeof(uint32_t), offset); |
| 573 | offset += Write(insn_count_and_handler_off, 2 * sizeof(uint16_t), offset); |
| 574 | } |
| 575 | // Leave offset pointing to the end of the try items. |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 576 | UNUSED(WriteUleb128(code_item->Handlers()->size(), offset)); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 577 | for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) { |
| 578 | size_t list_offset = offset + handlers->GetListOffset(); |
| 579 | uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 : |
| 580 | handlers->GetHandlers()->size(); |
| 581 | list_offset += WriteSleb128(size, list_offset); |
| 582 | for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) { |
| 583 | if (handler->GetTypeId() != nullptr) { |
| 584 | list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset); |
| 585 | } |
| 586 | list_offset += WriteUleb128(handler->GetAddress(), list_offset); |
| 587 | } |
| 588 | } |
| 589 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 590 | // TODO: Clean this up to properly calculate the size instead of assuming it doesn't change. |
| 591 | offset = code_item->GetOffset() + code_item->GetSize(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 592 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 593 | |
| 594 | if (compute_offsets_ && start != offset) { |
| 595 | header_->GetCollections().SetCodeItemsOffset(start); |
| 596 | } |
| 597 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 598 | } |
| 599 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 600 | uint32_t DexWriter::WriteClassDefs(uint32_t offset, bool reserve_only) { |
| 601 | const uint32_t start = offset; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 602 | uint32_t class_def_buffer[8]; |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 603 | for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 604 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeClassDefItem)); |
| 605 | if (reserve_only) { |
| 606 | offset += class_def->GetSize(); |
| 607 | } else { |
| 608 | class_def_buffer[0] = class_def->ClassType()->GetIndex(); |
| 609 | class_def_buffer[1] = class_def->GetAccessFlags(); |
| 610 | class_def_buffer[2] = class_def->Superclass() == nullptr ? dex::kDexNoIndex : |
| 611 | class_def->Superclass()->GetIndex(); |
| 612 | class_def_buffer[3] = class_def->InterfacesOffset(); |
| 613 | class_def_buffer[4] = class_def->SourceFile() == nullptr ? dex::kDexNoIndex : |
| 614 | class_def->SourceFile()->GetIndex(); |
| 615 | class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 : |
| 616 | class_def->Annotations()->GetOffset(); |
| 617 | class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 : |
| 618 | class_def->GetClassData()->GetOffset(); |
| 619 | class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 : |
| 620 | class_def->StaticValues()->GetOffset(); |
| 621 | offset += Write(class_def_buffer, class_def->GetSize(), offset); |
| 622 | } |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 623 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 624 | if (compute_offsets_ && start != offset) { |
| 625 | header_->GetCollections().SetClassDefsOffset(start); |
| 626 | } |
| 627 | return offset - start; |
| 628 | } |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 629 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 630 | uint32_t DexWriter::WriteClassDatas(uint32_t offset) { |
| 631 | const uint32_t start = offset; |
| 632 | for (const std::unique_ptr<dex_ir::ClassData>& class_data : |
| 633 | header_->GetCollections().ClassDatas()) { |
| 634 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeClassDataItem)); |
| 635 | ProcessOffset(&offset, class_data.get()); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 636 | offset += WriteUleb128(class_data->StaticFields()->size(), offset); |
| 637 | offset += WriteUleb128(class_data->InstanceFields()->size(), offset); |
| 638 | offset += WriteUleb128(class_data->DirectMethods()->size(), offset); |
| 639 | offset += WriteUleb128(class_data->VirtualMethods()->size(), offset); |
| 640 | offset += WriteEncodedFields(class_data->StaticFields(), offset); |
| 641 | offset += WriteEncodedFields(class_data->InstanceFields(), offset); |
| 642 | offset += WriteEncodedMethods(class_data->DirectMethods(), offset); |
| 643 | offset += WriteEncodedMethods(class_data->VirtualMethods(), offset); |
| 644 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 645 | if (compute_offsets_ && start != offset) { |
| 646 | header_->GetCollections().SetClassDatasOffset(start); |
| 647 | } |
| 648 | return offset - start; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 649 | } |
| 650 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 651 | uint32_t DexWriter::WriteCallSiteIds(uint32_t offset, bool reserve_only) { |
| 652 | const uint32_t start = offset; |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame] | 653 | uint32_t call_site_off[1]; |
| 654 | for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id : |
| 655 | header_->GetCollections().CallSiteIds()) { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 656 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCallSiteIdItem)); |
| 657 | if (reserve_only) { |
| 658 | offset += call_site_id->GetSize(); |
| 659 | } else { |
| 660 | call_site_off[0] = call_site_id->CallSiteItem()->GetOffset(); |
| 661 | offset += Write(call_site_off, call_site_id->GetSize(), offset); |
| 662 | } |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame] | 663 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 664 | if (compute_offsets_ && start != offset) { |
| 665 | header_->GetCollections().SetCallSiteIdsOffset(start); |
| 666 | } |
| 667 | return offset - start; |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame] | 668 | } |
| 669 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 670 | uint32_t DexWriter::WriteMethodHandles(uint32_t offset) { |
| 671 | const uint32_t start = offset; |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame] | 672 | uint16_t method_handle_buff[4]; |
| 673 | for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle : |
| 674 | header_->GetCollections().MethodHandleItems()) { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 675 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMethodHandleItem)); |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame] | 676 | method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType()); |
| 677 | method_handle_buff[1] = 0; // unused. |
| 678 | method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex(); |
| 679 | method_handle_buff[3] = 0; // unused. |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 680 | offset += Write(method_handle_buff, method_handle->GetSize(), offset); |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame] | 681 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 682 | if (compute_offsets_ && start != offset) { |
| 683 | header_->GetCollections().SetMethodHandleItemsOffset(start); |
| 684 | } |
| 685 | return offset - start; |
Jeff Hao | 5daee90 | 2017-04-27 18:00:38 -0700 | [diff] [blame] | 686 | } |
| 687 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 688 | uint32_t DexWriter::WriteMapItems(uint32_t offset, MapItemQueue* queue) { |
| 689 | // All the sections should already have been added. |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 690 | uint16_t uint16_buffer[2]; |
| 691 | uint32_t uint32_buffer[2]; |
| 692 | uint16_buffer[1] = 0; |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 693 | uint32_buffer[0] = queue->size(); |
| 694 | const uint32_t start = offset; |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 695 | offset += Write(uint32_buffer, sizeof(uint32_t), offset); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 696 | while (!queue->empty()) { |
| 697 | const MapItem& map_item = queue->top(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 698 | uint16_buffer[0] = map_item.type_; |
| 699 | uint32_buffer[0] = map_item.size_; |
| 700 | uint32_buffer[1] = map_item.offset_; |
| 701 | offset += Write(uint16_buffer, 2 * sizeof(uint16_t), offset); |
| 702 | offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 703 | queue->pop(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 704 | } |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 705 | return offset - start; |
| 706 | } |
| 707 | |
| 708 | uint32_t DexWriter::GenerateAndWriteMapItems(uint32_t offset) { |
| 709 | dex_ir::Collections& collection = header_->GetCollections(); |
| 710 | MapItemQueue queue; |
| 711 | |
| 712 | // Header and index section. |
| 713 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHeaderItem, 1, 0)); |
| 714 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringIdItem, |
| 715 | collection.StringIdsSize(), |
| 716 | collection.StringIdsOffset())); |
| 717 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeIdItem, |
| 718 | collection.TypeIdsSize(), |
| 719 | collection.TypeIdsOffset())); |
| 720 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeProtoIdItem, |
| 721 | collection.ProtoIdsSize(), |
| 722 | collection.ProtoIdsOffset())); |
| 723 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeFieldIdItem, |
| 724 | collection.FieldIdsSize(), |
| 725 | collection.FieldIdsOffset())); |
| 726 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodIdItem, |
| 727 | collection.MethodIdsSize(), |
| 728 | collection.MethodIdsOffset())); |
| 729 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDefItem, |
| 730 | collection.ClassDefsSize(), |
| 731 | collection.ClassDefsOffset())); |
| 732 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCallSiteIdItem, |
| 733 | collection.CallSiteIdsSize(), |
| 734 | collection.CallSiteIdsOffset())); |
| 735 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodHandleItem, |
| 736 | collection.MethodHandleItemsSize(), |
| 737 | collection.MethodHandleItemsOffset())); |
| 738 | // Data section. |
| 739 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, collection.MapListOffset())); |
| 740 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeList, |
| 741 | collection.TypeListsSize(), |
| 742 | collection.TypeListsOffset())); |
| 743 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetRefList, |
| 744 | collection.AnnotationSetRefListsSize(), |
| 745 | collection.AnnotationSetRefListsOffset())); |
| 746 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetItem, |
| 747 | collection.AnnotationSetItemsSize(), |
| 748 | collection.AnnotationSetItemsOffset())); |
| 749 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDataItem, |
| 750 | collection.ClassDatasSize(), |
| 751 | collection.ClassDatasOffset())); |
| 752 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCodeItem, |
| 753 | collection.CodeItemsSize(), |
| 754 | collection.CodeItemsOffset())); |
| 755 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringDataItem, |
| 756 | collection.StringDatasSize(), |
| 757 | collection.StringDatasOffset())); |
| 758 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeDebugInfoItem, |
| 759 | collection.DebugInfoItemsSize(), |
| 760 | collection.DebugInfoItemsOffset())); |
| 761 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationItem, |
| 762 | collection.AnnotationItemsSize(), |
| 763 | collection.AnnotationItemsOffset())); |
| 764 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeEncodedArrayItem, |
| 765 | collection.EncodedArrayItemsSize(), |
| 766 | collection.EncodedArrayItemsOffset())); |
| 767 | queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem, |
| 768 | collection.AnnotationsDirectoryItemsSize(), |
| 769 | collection.AnnotationsDirectoryItemsOffset())); |
| 770 | |
| 771 | // Write the map items. |
| 772 | return WriteMapItems(offset, &queue); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 773 | } |
| 774 | |
| 775 | void DexWriter::WriteHeader() { |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 776 | StandardDexFile::Header header; |
| 777 | static constexpr size_t kMagicAndVersionLen = |
| 778 | StandardDexFile::kDexMagicSize + StandardDexFile::kDexVersionLen; |
| 779 | std::copy_n(header_->Magic(), kMagicAndVersionLen, header.magic_); |
| 780 | header.checksum_ = header_->Checksum(); |
| 781 | std::copy_n(header_->Signature(), DexFile::kSha1DigestSize, header.signature_); |
| 782 | header.file_size_ = header_->FileSize(); |
| 783 | header.header_size_ = header_->GetSize(); |
| 784 | header.endian_tag_ = header_->EndianTag(); |
| 785 | header.link_size_ = header_->LinkSize(); |
| 786 | header.link_off_ = header_->LinkOffset(); |
| 787 | const dex_ir::Collections& collections = header_->GetCollections(); |
| 788 | header.map_off_ = collections.MapListOffset(); |
| 789 | header.string_ids_size_ = collections.StringIdsSize(); |
| 790 | header.string_ids_off_ = collections.StringIdsOffset(); |
| 791 | header.type_ids_size_ = collections.TypeIdsSize(); |
| 792 | header.type_ids_off_ = collections.TypeIdsOffset(); |
| 793 | header.proto_ids_size_ = collections.ProtoIdsSize(); |
| 794 | header.proto_ids_off_ = collections.ProtoIdsOffset(); |
| 795 | header.field_ids_size_ = collections.FieldIdsSize(); |
| 796 | header.field_ids_off_ = collections.FieldIdsOffset(); |
| 797 | header.method_ids_size_ = collections.MethodIdsSize(); |
| 798 | header.method_ids_off_ = collections.MethodIdsOffset(); |
| 799 | header.class_defs_size_ = collections.ClassDefsSize(); |
| 800 | header.class_defs_off_ = collections.ClassDefsOffset(); |
| 801 | header.data_size_ = header_->DataSize(); |
| 802 | header.data_off_ = header_->DataOffset(); |
| 803 | |
| 804 | static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec"); |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 805 | UNUSED(Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u)); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 806 | } |
| 807 | |
Jeff Hao | ea7c629 | 2016-11-14 18:10:16 -0800 | [diff] [blame] | 808 | void DexWriter::WriteMemMap() { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 809 | // Starting offset is right after the header. |
| 810 | uint32_t offset = sizeof(StandardDexFile::Header); |
| 811 | |
| 812 | dex_ir::Collections& collection = header_->GetCollections(); |
| 813 | |
| 814 | // Based on: https://source.android.com/devices/tech/dalvik/dex-format |
| 815 | // Since the offsets may not be calculated already, the writing must be done in the correct order. |
| 816 | const uint32_t string_ids_offset = offset; |
| 817 | offset += WriteStringIds(offset, /*reserve_only*/ true); |
| 818 | offset += WriteTypeIds(offset); |
| 819 | const uint32_t proto_ids_offset = offset; |
| 820 | offset += WriteProtoIds(offset, /*reserve_only*/ true); |
| 821 | offset += WriteFieldIds(offset); |
| 822 | offset += WriteMethodIds(offset); |
| 823 | const uint32_t class_defs_offset = offset; |
| 824 | offset += WriteClassDefs(offset, /*reserve_only*/ true); |
| 825 | const uint32_t call_site_ids_offset = offset; |
| 826 | offset += WriteCallSiteIds(offset, /*reserve_only*/ true); |
| 827 | offset += WriteMethodHandles(offset); |
| 828 | |
| 829 | uint32_t data_offset_ = 0u; |
| 830 | if (compute_offsets_) { |
| 831 | // Data section. |
| 832 | offset = RoundUp(offset, kDataSectionAlignment); |
| 833 | data_offset_ = offset; |
| 834 | } |
| 835 | |
| 836 | // Write code item first to minimize the space required for encoded methods. |
| 837 | // Reserve code item space since we need the debug offsets to actually write them. |
| 838 | const uint32_t code_items_offset = offset; |
| 839 | offset += WriteCodeItems(offset, /*reserve_only*/ true); |
| 840 | // Write debug info section. |
| 841 | offset += WriteDebugInfoItems(offset); |
| 842 | // Actually write code items since debug info offsets are calculated now. |
| 843 | WriteCodeItems(code_items_offset, /*reserve_only*/ false); |
| 844 | |
| 845 | offset += WriteEncodedArrays(offset); |
| 846 | offset += WriteAnnotations(offset); |
| 847 | offset += WriteAnnotationSets(offset); |
| 848 | offset += WriteAnnotationSetRefs(offset); |
| 849 | offset += WriteAnnotationsDirectories(offset); |
| 850 | offset += WriteTypeLists(offset); |
| 851 | offset += WriteClassDatas(offset); |
| 852 | offset += WriteStringDatas(offset); |
| 853 | |
| 854 | // Write delayed id sections that depend on data sections. |
| 855 | WriteStringIds(string_ids_offset, /*reserve_only*/ false); |
| 856 | WriteProtoIds(proto_ids_offset, /*reserve_only*/ false); |
| 857 | WriteClassDefs(class_defs_offset, /*reserve_only*/ false); |
| 858 | WriteCallSiteIds(call_site_ids_offset, /*reserve_only*/ false); |
| 859 | |
| 860 | // Write the map list. |
| 861 | if (compute_offsets_) { |
| 862 | offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMapList)); |
| 863 | collection.SetMapListOffset(offset); |
| 864 | } else { |
| 865 | offset = collection.MapListOffset(); |
| 866 | } |
| 867 | offset += GenerateAndWriteMapItems(offset); |
| 868 | offset = RoundUp(offset, kDataSectionAlignment); |
| 869 | |
| 870 | // Map items are included in the data section. |
| 871 | if (compute_offsets_) { |
| 872 | header_->SetDataSize(offset - data_offset_); |
| 873 | if (header_->DataSize() != 0) { |
| 874 | // Offset must be zero when the size is zero. |
| 875 | header_->SetDataOffset(data_offset_); |
| 876 | } else { |
| 877 | header_->SetDataOffset(0u); |
| 878 | } |
| 879 | } |
| 880 | |
| 881 | // TODO: Write link data? |
| 882 | |
| 883 | // Write header last. |
| 884 | if (compute_offsets_) { |
| 885 | header_->SetFileSize(offset); |
| 886 | } |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 887 | WriteHeader(); |
| 888 | } |
| 889 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 890 | void DexWriter::Output(dex_ir::Header* header, |
| 891 | MemMap* mem_map, |
| 892 | DexLayout* dex_layout, |
| 893 | bool compute_offsets, |
| 894 | CompactDexLevel compact_dex_level) { |
| 895 | CHECK(dex_layout != nullptr); |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 896 | std::unique_ptr<DexWriter> writer; |
| 897 | if (compact_dex_level != CompactDexLevel::kCompactDexLevelNone) { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 898 | writer.reset(new CompactDexWriter(header, mem_map, dex_layout, compact_dex_level)); |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 899 | } else { |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 900 | writer.reset(new DexWriter(header, mem_map, dex_layout, compute_offsets)); |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 901 | } |
| 902 | writer->WriteMemMap(); |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 903 | } |
| 904 | |
Mathieu Chartier | 3e0c517 | 2017-11-12 12:58:40 -0800 | [diff] [blame^] | 905 | void MapItemQueue::AddIfNotEmpty(const MapItem& item) { |
| 906 | if (item.size_ != 0) { |
| 907 | push(item); |
| 908 | } |
| 909 | } |
| 910 | |
Jeff Hao | a862100 | 2016-10-04 18:13:44 +0000 | [diff] [blame] | 911 | } // namespace art |