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