blob: 58f1ec7b0875be87c5ed385882ad3fef8bab1d5c [file] [log] [blame]
Vladimir Markoc91df2d2015-04-23 09:29:21 +00001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_COMPILER_UTILS_TEST_DEX_FILE_BUILDER_H_
18#define ART_COMPILER_UTILS_TEST_DEX_FILE_BUILDER_H_
19
Vladimir Marko9bdf1082016-01-21 12:15:52 +000020#include <zlib.h>
Vladimir Markoc91df2d2015-04-23 09:29:21 +000021
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070022#include <cstring>
23#include <map>
24#include <set>
25#include <vector>
26
Andreas Gampe57943812017-12-06 21:39:13 -080027#include <android-base/logging.h>
28
Vladimir Marko80afd022015-05-19 18:08:00 +010029#include "base/bit_utils.h"
David Sehr013fd802018-01-11 22:55:24 -080030#include "dex/art_dex_file_loader.h"
David Sehr9e734c72018-01-04 17:56:19 -080031#include "dex/dex_file_loader.h"
32#include "dex/standard_dex_file.h"
Vladimir Markoc91df2d2015-04-23 09:29:21 +000033
34namespace art {
35
36class TestDexFileBuilder {
37 public:
38 TestDexFileBuilder()
39 : strings_(), types_(), fields_(), protos_(), dex_file_data_() {
40 }
41
42 void AddString(const std::string& str) {
43 CHECK(dex_file_data_.empty());
44 auto it = strings_.emplace(str, IdxAndDataOffset()).first;
45 CHECK_LT(it->first.length(), 128u); // Don't allow multi-byte length in uleb128.
46 }
47
48 void AddType(const std::string& descriptor) {
49 CHECK(dex_file_data_.empty());
50 AddString(descriptor);
51 types_.emplace(descriptor, 0u);
52 }
53
54 void AddField(const std::string& class_descriptor, const std::string& type,
55 const std::string& name) {
56 CHECK(dex_file_data_.empty());
57 AddType(class_descriptor);
58 AddType(type);
59 AddString(name);
60 FieldKey key = { class_descriptor, type, name };
61 fields_.emplace(key, 0u);
62 }
63
64 void AddMethod(const std::string& class_descriptor, const std::string& signature,
65 const std::string& name) {
66 CHECK(dex_file_data_.empty());
67 AddType(class_descriptor);
68 AddString(name);
69
70 ProtoKey proto_key = CreateProtoKey(signature);
71 AddString(proto_key.shorty);
72 AddType(proto_key.return_type);
73 for (const auto& arg_type : proto_key.args) {
74 AddType(arg_type);
75 }
76 auto it = protos_.emplace(proto_key, IdxAndDataOffset()).first;
77 const ProtoKey* proto = &it->first; // Valid as long as the element remains in protos_.
78
79 MethodKey method_key = {
80 class_descriptor, name, proto
81 };
82 methods_.emplace(method_key, 0u);
83 }
84
85 // NOTE: The builder holds the actual data, so it must live as long as the dex file.
86 std::unique_ptr<const DexFile> Build(const std::string& dex_location) {
87 CHECK(dex_file_data_.empty());
88 union {
89 uint8_t data[sizeof(DexFile::Header)];
90 uint64_t force_alignment;
91 } header_data;
92 std::memset(header_data.data, 0, sizeof(header_data.data));
93 DexFile::Header* header = reinterpret_cast<DexFile::Header*>(&header_data.data);
Mathieu Chartier292567e2017-10-12 13:24:38 -070094 std::copy_n(StandardDexFile::kDexMagic, 4u, header->magic_);
95 std::copy_n(StandardDexFile::kDexMagicVersions[0], 4u, header->magic_ + 4u);
Andreas Gampe3a2bd292016-01-26 17:23:47 -080096 header->header_size_ = sizeof(DexFile::Header);
Vladimir Markoc91df2d2015-04-23 09:29:21 +000097 header->endian_tag_ = DexFile::kDexEndianConstant;
98 header->link_size_ = 0u; // Unused.
99 header->link_off_ = 0u; // Unused.
Andreas Gampe3a2bd292016-01-26 17:23:47 -0800100 header->map_off_ = 0u; // Unused. TODO: This is wrong. Dex files created by this builder
101 // cannot be verified. b/26808512
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000102
103 uint32_t data_section_size = 0u;
104
105 uint32_t string_ids_offset = sizeof(DexFile::Header);
106 uint32_t string_idx = 0u;
107 for (auto& entry : strings_) {
108 entry.second.idx = string_idx;
109 string_idx += 1u;
110 entry.second.data_offset = data_section_size;
111 data_section_size += entry.first.length() + 1u /* length */ + 1u /* null-terminator */;
112 }
113 header->string_ids_size_ = strings_.size();
114 header->string_ids_off_ = strings_.empty() ? 0u : string_ids_offset;
115
116 uint32_t type_ids_offset = string_ids_offset + strings_.size() * sizeof(DexFile::StringId);
117 uint32_t type_idx = 0u;
118 for (auto& entry : types_) {
119 entry.second = type_idx;
120 type_idx += 1u;
121 }
122 header->type_ids_size_ = types_.size();
123 header->type_ids_off_ = types_.empty() ? 0u : type_ids_offset;
124
125 uint32_t proto_ids_offset = type_ids_offset + types_.size() * sizeof(DexFile::TypeId);
126 uint32_t proto_idx = 0u;
127 for (auto& entry : protos_) {
128 entry.second.idx = proto_idx;
129 proto_idx += 1u;
130 size_t num_args = entry.first.args.size();
131 if (num_args != 0u) {
132 entry.second.data_offset = RoundUp(data_section_size, 4u);
133 data_section_size = entry.second.data_offset + 4u + num_args * sizeof(DexFile::TypeItem);
134 } else {
135 entry.second.data_offset = 0u;
136 }
137 }
138 header->proto_ids_size_ = protos_.size();
139 header->proto_ids_off_ = protos_.empty() ? 0u : proto_ids_offset;
140
141 uint32_t field_ids_offset = proto_ids_offset + protos_.size() * sizeof(DexFile::ProtoId);
142 uint32_t field_idx = 0u;
143 for (auto& entry : fields_) {
144 entry.second = field_idx;
145 field_idx += 1u;
146 }
147 header->field_ids_size_ = fields_.size();
148 header->field_ids_off_ = fields_.empty() ? 0u : field_ids_offset;
149
150 uint32_t method_ids_offset = field_ids_offset + fields_.size() * sizeof(DexFile::FieldId);
151 uint32_t method_idx = 0u;
152 for (auto& entry : methods_) {
153 entry.second = method_idx;
154 method_idx += 1u;
155 }
156 header->method_ids_size_ = methods_.size();
157 header->method_ids_off_ = methods_.empty() ? 0u : method_ids_offset;
158
159 // No class defs.
160 header->class_defs_size_ = 0u;
161 header->class_defs_off_ = 0u;
162
163 uint32_t data_section_offset = method_ids_offset + methods_.size() * sizeof(DexFile::MethodId);
164 header->data_size_ = data_section_size;
165 header->data_off_ = (data_section_size != 0u) ? data_section_offset : 0u;
166
167 uint32_t total_size = data_section_offset + data_section_size;
168
169 dex_file_data_.resize(total_size);
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000170
171 for (const auto& entry : strings_) {
172 CHECK_LT(entry.first.size(), 128u);
173 uint32_t raw_offset = data_section_offset + entry.second.data_offset;
174 dex_file_data_[raw_offset] = static_cast<uint8_t>(entry.first.size());
175 std::memcpy(&dex_file_data_[raw_offset + 1], entry.first.c_str(), entry.first.size() + 1);
176 Write32(string_ids_offset + entry.second.idx * sizeof(DexFile::StringId), raw_offset);
177 }
178
179 for (const auto& entry : types_) {
180 Write32(type_ids_offset + entry.second * sizeof(DexFile::TypeId), GetStringIdx(entry.first));
181 ++type_idx;
182 }
183
184 for (const auto& entry : protos_) {
185 size_t num_args = entry.first.args.size();
186 uint32_t type_list_offset =
187 (num_args != 0u) ? data_section_offset + entry.second.data_offset : 0u;
188 uint32_t raw_offset = proto_ids_offset + entry.second.idx * sizeof(DexFile::ProtoId);
189 Write32(raw_offset + 0u, GetStringIdx(entry.first.shorty));
190 Write16(raw_offset + 4u, GetTypeIdx(entry.first.return_type));
191 Write32(raw_offset + 8u, type_list_offset);
192 if (num_args != 0u) {
193 CHECK_NE(entry.second.data_offset, 0u);
194 Write32(type_list_offset, num_args);
195 for (size_t i = 0; i != num_args; ++i) {
196 Write16(type_list_offset + 4u + i * sizeof(DexFile::TypeItem),
197 GetTypeIdx(entry.first.args[i]));
198 }
199 }
200 }
201
202 for (const auto& entry : fields_) {
203 uint32_t raw_offset = field_ids_offset + entry.second * sizeof(DexFile::FieldId);
204 Write16(raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor));
205 Write16(raw_offset + 2u, GetTypeIdx(entry.first.type));
206 Write32(raw_offset + 4u, GetStringIdx(entry.first.name));
207 }
208
209 for (const auto& entry : methods_) {
210 uint32_t raw_offset = method_ids_offset + entry.second * sizeof(DexFile::MethodId);
211 Write16(raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor));
212 auto it = protos_.find(*entry.first.proto);
213 CHECK(it != protos_.end());
214 Write16(raw_offset + 2u, it->second.idx);
215 Write32(raw_offset + 4u, GetStringIdx(entry.first.name));
216 }
217
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000218 // Leave signature as zeros.
219
220 header->file_size_ = dex_file_data_.size();
Andreas Gampe3a2bd292016-01-26 17:23:47 -0800221
222 // Write the complete header early, as part of it needs to be checksummed.
223 std::memcpy(&dex_file_data_[0], header_data.data, sizeof(DexFile::Header));
224
225 // Checksum starts after the checksum field.
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000226 size_t skip = sizeof(header->magic_) + sizeof(header->checksum_);
Andreas Gampe3a2bd292016-01-26 17:23:47 -0800227 header->checksum_ = adler32(adler32(0L, Z_NULL, 0),
228 dex_file_data_.data() + skip,
229 dex_file_data_.size() - skip);
230
231 // Write the complete header again, just simpler that way.
Vladimir Marko9bdf1082016-01-21 12:15:52 +0000232 std::memcpy(&dex_file_data_[0], header_data.data, sizeof(DexFile::Header));
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000233
Aart Bik37d6a3b2016-06-21 18:30:10 -0700234 static constexpr bool kVerify = false;
235 static constexpr bool kVerifyChecksum = false;
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000236 std::string error_msg;
David Sehr013fd802018-01-11 22:55:24 -0800237 const ArtDexFileLoader dex_file_loader;
238 std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(
Aart Bik37d6a3b2016-06-21 18:30:10 -0700239 &dex_file_data_[0],
240 dex_file_data_.size(),
241 dex_location,
242 0u,
243 nullptr,
244 kVerify,
245 kVerifyChecksum,
246 &error_msg));
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000247 CHECK(dex_file != nullptr) << error_msg;
Pirama Arumuga Nainar0600cdc2015-09-14 11:00:16 -0700248 return dex_file;
Vladimir Markoc91df2d2015-04-23 09:29:21 +0000249 }
250
251 uint32_t GetStringIdx(const std::string& type) {
252 auto it = strings_.find(type);
253 CHECK(it != strings_.end());
254 return it->second.idx;
255 }
256
257 uint32_t GetTypeIdx(const std::string& type) {
258 auto it = types_.find(type);
259 CHECK(it != types_.end());
260 return it->second;
261 }
262
263 uint32_t GetFieldIdx(const std::string& class_descriptor, const std::string& type,
264 const std::string& name) {
265 FieldKey key = { class_descriptor, type, name };
266 auto it = fields_.find(key);
267 CHECK(it != fields_.end());
268 return it->second;
269 }
270
271 uint32_t GetMethodIdx(const std::string& class_descriptor, const std::string& signature,
272 const std::string& name) {
273 ProtoKey proto_key = CreateProtoKey(signature);
274 MethodKey method_key = { class_descriptor, name, &proto_key };
275 auto it = methods_.find(method_key);
276 CHECK(it != methods_.end());
277 return it->second;
278 }
279
280 private:
281 struct IdxAndDataOffset {
282 uint32_t idx;
283 uint32_t data_offset;
284 };
285
286 struct FieldKey {
287 const std::string class_descriptor;
288 const std::string type;
289 const std::string name;
290 };
291 struct FieldKeyComparator {
292 bool operator()(const FieldKey& lhs, const FieldKey& rhs) const {
293 if (lhs.class_descriptor != rhs.class_descriptor) {
294 return lhs.class_descriptor < rhs.class_descriptor;
295 }
296 if (lhs.name != rhs.name) {
297 return lhs.name < rhs.name;
298 }
299 return lhs.type < rhs.type;
300 }
301 };
302
303 struct ProtoKey {
304 std::string shorty;
305 std::string return_type;
306 std::vector<std::string> args;
307 };
308 struct ProtoKeyComparator {
309 bool operator()(const ProtoKey& lhs, const ProtoKey& rhs) const {
310 if (lhs.return_type != rhs.return_type) {
311 return lhs.return_type < rhs.return_type;
312 }
313 size_t min_args = std::min(lhs.args.size(), rhs.args.size());
314 for (size_t i = 0; i != min_args; ++i) {
315 if (lhs.args[i] != rhs.args[i]) {
316 return lhs.args[i] < rhs.args[i];
317 }
318 }
319 return lhs.args.size() < rhs.args.size();
320 }
321 };
322
323 struct MethodKey {
324 std::string class_descriptor;
325 std::string name;
326 const ProtoKey* proto;
327 };
328 struct MethodKeyComparator {
329 bool operator()(const MethodKey& lhs, const MethodKey& rhs) const {
330 if (lhs.class_descriptor != rhs.class_descriptor) {
331 return lhs.class_descriptor < rhs.class_descriptor;
332 }
333 if (lhs.name != rhs.name) {
334 return lhs.name < rhs.name;
335 }
336 return ProtoKeyComparator()(*lhs.proto, *rhs.proto);
337 }
338 };
339
340 ProtoKey CreateProtoKey(const std::string& signature) {
341 CHECK_EQ(signature[0], '(');
342 const char* args = signature.c_str() + 1;
343 const char* args_end = std::strchr(args, ')');
344 CHECK(args_end != nullptr);
345 const char* return_type = args_end + 1;
346
347 ProtoKey key = {
348 std::string() + ((*return_type == '[') ? 'L' : *return_type),
349 return_type,
350 std::vector<std::string>()
351 };
352 while (args != args_end) {
353 key.shorty += (*args == '[') ? 'L' : *args;
354 const char* arg_start = args;
355 while (*args == '[') {
356 ++args;
357 }
358 if (*args == 'L') {
359 do {
360 ++args;
361 CHECK_NE(args, args_end);
362 } while (*args != ';');
363 }
364 ++args;
365 key.args.emplace_back(arg_start, args);
366 }
367 return key;
368 }
369
370 void Write32(size_t offset, uint32_t value) {
371 CHECK_LE(offset + 4u, dex_file_data_.size());
372 CHECK_EQ(dex_file_data_[offset + 0], 0u);
373 CHECK_EQ(dex_file_data_[offset + 1], 0u);
374 CHECK_EQ(dex_file_data_[offset + 2], 0u);
375 CHECK_EQ(dex_file_data_[offset + 3], 0u);
376 dex_file_data_[offset + 0] = static_cast<uint8_t>(value >> 0);
377 dex_file_data_[offset + 1] = static_cast<uint8_t>(value >> 8);
378 dex_file_data_[offset + 2] = static_cast<uint8_t>(value >> 16);
379 dex_file_data_[offset + 3] = static_cast<uint8_t>(value >> 24);
380 }
381
382 void Write16(size_t offset, uint32_t value) {
383 CHECK_LE(value, 0xffffu);
384 CHECK_LE(offset + 2u, dex_file_data_.size());
385 CHECK_EQ(dex_file_data_[offset + 0], 0u);
386 CHECK_EQ(dex_file_data_[offset + 1], 0u);
387 dex_file_data_[offset + 0] = static_cast<uint8_t>(value >> 0);
388 dex_file_data_[offset + 1] = static_cast<uint8_t>(value >> 8);
389 }
390
391 std::map<std::string, IdxAndDataOffset> strings_;
392 std::map<std::string, uint32_t> types_;
393 std::map<FieldKey, uint32_t, FieldKeyComparator> fields_;
394 std::map<ProtoKey, IdxAndDataOffset, ProtoKeyComparator> protos_;
395 std::map<MethodKey, uint32_t, MethodKeyComparator> methods_;
396
397 std::vector<uint8_t> dex_file_data_;
398};
399
400} // namespace art
401
402#endif // ART_COMPILER_UTILS_TEST_DEX_FILE_BUILDER_H_