blob: ab039aa2155d4388d46624bdf0e56cdd549b16aa [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
20#include <cstring>
21#include <set>
22#include <map>
23#include <vector>
24
25#include "dex_file.h"
26#include "utils.h"
27
28namespace art {
29
30class TestDexFileBuilder {
31 public:
32 TestDexFileBuilder()
33 : strings_(), types_(), fields_(), protos_(), dex_file_data_() {
34 }
35
36 void AddString(const std::string& str) {
37 CHECK(dex_file_data_.empty());
38 auto it = strings_.emplace(str, IdxAndDataOffset()).first;
39 CHECK_LT(it->first.length(), 128u); // Don't allow multi-byte length in uleb128.
40 }
41
42 void AddType(const std::string& descriptor) {
43 CHECK(dex_file_data_.empty());
44 AddString(descriptor);
45 types_.emplace(descriptor, 0u);
46 }
47
48 void AddField(const std::string& class_descriptor, const std::string& type,
49 const std::string& name) {
50 CHECK(dex_file_data_.empty());
51 AddType(class_descriptor);
52 AddType(type);
53 AddString(name);
54 FieldKey key = { class_descriptor, type, name };
55 fields_.emplace(key, 0u);
56 }
57
58 void AddMethod(const std::string& class_descriptor, const std::string& signature,
59 const std::string& name) {
60 CHECK(dex_file_data_.empty());
61 AddType(class_descriptor);
62 AddString(name);
63
64 ProtoKey proto_key = CreateProtoKey(signature);
65 AddString(proto_key.shorty);
66 AddType(proto_key.return_type);
67 for (const auto& arg_type : proto_key.args) {
68 AddType(arg_type);
69 }
70 auto it = protos_.emplace(proto_key, IdxAndDataOffset()).first;
71 const ProtoKey* proto = &it->first; // Valid as long as the element remains in protos_.
72
73 MethodKey method_key = {
74 class_descriptor, name, proto
75 };
76 methods_.emplace(method_key, 0u);
77 }
78
79 // NOTE: The builder holds the actual data, so it must live as long as the dex file.
80 std::unique_ptr<const DexFile> Build(const std::string& dex_location) {
81 CHECK(dex_file_data_.empty());
82 union {
83 uint8_t data[sizeof(DexFile::Header)];
84 uint64_t force_alignment;
85 } header_data;
86 std::memset(header_data.data, 0, sizeof(header_data.data));
87 DexFile::Header* header = reinterpret_cast<DexFile::Header*>(&header_data.data);
88 std::copy_n(DexFile::kDexMagic, 4u, header->magic_);
89 std::copy_n(DexFile::kDexMagicVersion, 4u, header->magic_ + 4u);
90 header->header_size_ = sizeof(header);
91 header->endian_tag_ = DexFile::kDexEndianConstant;
92 header->link_size_ = 0u; // Unused.
93 header->link_off_ = 0u; // Unused.
94 header->map_off_ = 0u; // Unused.
95
96 uint32_t data_section_size = 0u;
97
98 uint32_t string_ids_offset = sizeof(DexFile::Header);
99 uint32_t string_idx = 0u;
100 for (auto& entry : strings_) {
101 entry.second.idx = string_idx;
102 string_idx += 1u;
103 entry.second.data_offset = data_section_size;
104 data_section_size += entry.first.length() + 1u /* length */ + 1u /* null-terminator */;
105 }
106 header->string_ids_size_ = strings_.size();
107 header->string_ids_off_ = strings_.empty() ? 0u : string_ids_offset;
108
109 uint32_t type_ids_offset = string_ids_offset + strings_.size() * sizeof(DexFile::StringId);
110 uint32_t type_idx = 0u;
111 for (auto& entry : types_) {
112 entry.second = type_idx;
113 type_idx += 1u;
114 }
115 header->type_ids_size_ = types_.size();
116 header->type_ids_off_ = types_.empty() ? 0u : type_ids_offset;
117
118 uint32_t proto_ids_offset = type_ids_offset + types_.size() * sizeof(DexFile::TypeId);
119 uint32_t proto_idx = 0u;
120 for (auto& entry : protos_) {
121 entry.second.idx = proto_idx;
122 proto_idx += 1u;
123 size_t num_args = entry.first.args.size();
124 if (num_args != 0u) {
125 entry.second.data_offset = RoundUp(data_section_size, 4u);
126 data_section_size = entry.second.data_offset + 4u + num_args * sizeof(DexFile::TypeItem);
127 } else {
128 entry.second.data_offset = 0u;
129 }
130 }
131 header->proto_ids_size_ = protos_.size();
132 header->proto_ids_off_ = protos_.empty() ? 0u : proto_ids_offset;
133
134 uint32_t field_ids_offset = proto_ids_offset + protos_.size() * sizeof(DexFile::ProtoId);
135 uint32_t field_idx = 0u;
136 for (auto& entry : fields_) {
137 entry.second = field_idx;
138 field_idx += 1u;
139 }
140 header->field_ids_size_ = fields_.size();
141 header->field_ids_off_ = fields_.empty() ? 0u : field_ids_offset;
142
143 uint32_t method_ids_offset = field_ids_offset + fields_.size() * sizeof(DexFile::FieldId);
144 uint32_t method_idx = 0u;
145 for (auto& entry : methods_) {
146 entry.second = method_idx;
147 method_idx += 1u;
148 }
149 header->method_ids_size_ = methods_.size();
150 header->method_ids_off_ = methods_.empty() ? 0u : method_ids_offset;
151
152 // No class defs.
153 header->class_defs_size_ = 0u;
154 header->class_defs_off_ = 0u;
155
156 uint32_t data_section_offset = method_ids_offset + methods_.size() * sizeof(DexFile::MethodId);
157 header->data_size_ = data_section_size;
158 header->data_off_ = (data_section_size != 0u) ? data_section_offset : 0u;
159
160 uint32_t total_size = data_section_offset + data_section_size;
161
162 dex_file_data_.resize(total_size);
163 std::memcpy(&dex_file_data_[0], header_data.data, sizeof(DexFile::Header));
164
165 for (const auto& entry : strings_) {
166 CHECK_LT(entry.first.size(), 128u);
167 uint32_t raw_offset = data_section_offset + entry.second.data_offset;
168 dex_file_data_[raw_offset] = static_cast<uint8_t>(entry.first.size());
169 std::memcpy(&dex_file_data_[raw_offset + 1], entry.first.c_str(), entry.first.size() + 1);
170 Write32(string_ids_offset + entry.second.idx * sizeof(DexFile::StringId), raw_offset);
171 }
172
173 for (const auto& entry : types_) {
174 Write32(type_ids_offset + entry.second * sizeof(DexFile::TypeId), GetStringIdx(entry.first));
175 ++type_idx;
176 }
177
178 for (const auto& entry : protos_) {
179 size_t num_args = entry.first.args.size();
180 uint32_t type_list_offset =
181 (num_args != 0u) ? data_section_offset + entry.second.data_offset : 0u;
182 uint32_t raw_offset = proto_ids_offset + entry.second.idx * sizeof(DexFile::ProtoId);
183 Write32(raw_offset + 0u, GetStringIdx(entry.first.shorty));
184 Write16(raw_offset + 4u, GetTypeIdx(entry.first.return_type));
185 Write32(raw_offset + 8u, type_list_offset);
186 if (num_args != 0u) {
187 CHECK_NE(entry.second.data_offset, 0u);
188 Write32(type_list_offset, num_args);
189 for (size_t i = 0; i != num_args; ++i) {
190 Write16(type_list_offset + 4u + i * sizeof(DexFile::TypeItem),
191 GetTypeIdx(entry.first.args[i]));
192 }
193 }
194 }
195
196 for (const auto& entry : fields_) {
197 uint32_t raw_offset = field_ids_offset + entry.second * sizeof(DexFile::FieldId);
198 Write16(raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor));
199 Write16(raw_offset + 2u, GetTypeIdx(entry.first.type));
200 Write32(raw_offset + 4u, GetStringIdx(entry.first.name));
201 }
202
203 for (const auto& entry : methods_) {
204 uint32_t raw_offset = method_ids_offset + entry.second * sizeof(DexFile::MethodId);
205 Write16(raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor));
206 auto it = protos_.find(*entry.first.proto);
207 CHECK(it != protos_.end());
208 Write16(raw_offset + 2u, it->second.idx);
209 Write32(raw_offset + 4u, GetStringIdx(entry.first.name));
210 }
211
212 // Leave checksum and signature as zeros.
213
214 std::string error_msg;
215 std::unique_ptr<const DexFile> dex_file(DexFile::Open(
216 &dex_file_data_[0], dex_file_data_.size(), dex_location, 0u, nullptr, &error_msg));
217 CHECK(dex_file != nullptr) << error_msg;
218 return std::move(dex_file);
219 }
220
221 uint32_t GetStringIdx(const std::string& type) {
222 auto it = strings_.find(type);
223 CHECK(it != strings_.end());
224 return it->second.idx;
225 }
226
227 uint32_t GetTypeIdx(const std::string& type) {
228 auto it = types_.find(type);
229 CHECK(it != types_.end());
230 return it->second;
231 }
232
233 uint32_t GetFieldIdx(const std::string& class_descriptor, const std::string& type,
234 const std::string& name) {
235 FieldKey key = { class_descriptor, type, name };
236 auto it = fields_.find(key);
237 CHECK(it != fields_.end());
238 return it->second;
239 }
240
241 uint32_t GetMethodIdx(const std::string& class_descriptor, const std::string& signature,
242 const std::string& name) {
243 ProtoKey proto_key = CreateProtoKey(signature);
244 MethodKey method_key = { class_descriptor, name, &proto_key };
245 auto it = methods_.find(method_key);
246 CHECK(it != methods_.end());
247 return it->second;
248 }
249
250 private:
251 struct IdxAndDataOffset {
252 uint32_t idx;
253 uint32_t data_offset;
254 };
255
256 struct FieldKey {
257 const std::string class_descriptor;
258 const std::string type;
259 const std::string name;
260 };
261 struct FieldKeyComparator {
262 bool operator()(const FieldKey& lhs, const FieldKey& rhs) const {
263 if (lhs.class_descriptor != rhs.class_descriptor) {
264 return lhs.class_descriptor < rhs.class_descriptor;
265 }
266 if (lhs.name != rhs.name) {
267 return lhs.name < rhs.name;
268 }
269 return lhs.type < rhs.type;
270 }
271 };
272
273 struct ProtoKey {
274 std::string shorty;
275 std::string return_type;
276 std::vector<std::string> args;
277 };
278 struct ProtoKeyComparator {
279 bool operator()(const ProtoKey& lhs, const ProtoKey& rhs) const {
280 if (lhs.return_type != rhs.return_type) {
281 return lhs.return_type < rhs.return_type;
282 }
283 size_t min_args = std::min(lhs.args.size(), rhs.args.size());
284 for (size_t i = 0; i != min_args; ++i) {
285 if (lhs.args[i] != rhs.args[i]) {
286 return lhs.args[i] < rhs.args[i];
287 }
288 }
289 return lhs.args.size() < rhs.args.size();
290 }
291 };
292
293 struct MethodKey {
294 std::string class_descriptor;
295 std::string name;
296 const ProtoKey* proto;
297 };
298 struct MethodKeyComparator {
299 bool operator()(const MethodKey& lhs, const MethodKey& rhs) const {
300 if (lhs.class_descriptor != rhs.class_descriptor) {
301 return lhs.class_descriptor < rhs.class_descriptor;
302 }
303 if (lhs.name != rhs.name) {
304 return lhs.name < rhs.name;
305 }
306 return ProtoKeyComparator()(*lhs.proto, *rhs.proto);
307 }
308 };
309
310 ProtoKey CreateProtoKey(const std::string& signature) {
311 CHECK_EQ(signature[0], '(');
312 const char* args = signature.c_str() + 1;
313 const char* args_end = std::strchr(args, ')');
314 CHECK(args_end != nullptr);
315 const char* return_type = args_end + 1;
316
317 ProtoKey key = {
318 std::string() + ((*return_type == '[') ? 'L' : *return_type),
319 return_type,
320 std::vector<std::string>()
321 };
322 while (args != args_end) {
323 key.shorty += (*args == '[') ? 'L' : *args;
324 const char* arg_start = args;
325 while (*args == '[') {
326 ++args;
327 }
328 if (*args == 'L') {
329 do {
330 ++args;
331 CHECK_NE(args, args_end);
332 } while (*args != ';');
333 }
334 ++args;
335 key.args.emplace_back(arg_start, args);
336 }
337 return key;
338 }
339
340 void Write32(size_t offset, uint32_t value) {
341 CHECK_LE(offset + 4u, dex_file_data_.size());
342 CHECK_EQ(dex_file_data_[offset + 0], 0u);
343 CHECK_EQ(dex_file_data_[offset + 1], 0u);
344 CHECK_EQ(dex_file_data_[offset + 2], 0u);
345 CHECK_EQ(dex_file_data_[offset + 3], 0u);
346 dex_file_data_[offset + 0] = static_cast<uint8_t>(value >> 0);
347 dex_file_data_[offset + 1] = static_cast<uint8_t>(value >> 8);
348 dex_file_data_[offset + 2] = static_cast<uint8_t>(value >> 16);
349 dex_file_data_[offset + 3] = static_cast<uint8_t>(value >> 24);
350 }
351
352 void Write16(size_t offset, uint32_t value) {
353 CHECK_LE(value, 0xffffu);
354 CHECK_LE(offset + 2u, dex_file_data_.size());
355 CHECK_EQ(dex_file_data_[offset + 0], 0u);
356 CHECK_EQ(dex_file_data_[offset + 1], 0u);
357 dex_file_data_[offset + 0] = static_cast<uint8_t>(value >> 0);
358 dex_file_data_[offset + 1] = static_cast<uint8_t>(value >> 8);
359 }
360
361 std::map<std::string, IdxAndDataOffset> strings_;
362 std::map<std::string, uint32_t> types_;
363 std::map<FieldKey, uint32_t, FieldKeyComparator> fields_;
364 std::map<ProtoKey, IdxAndDataOffset, ProtoKeyComparator> protos_;
365 std::map<MethodKey, uint32_t, MethodKeyComparator> methods_;
366
367 std::vector<uint8_t> dex_file_data_;
368};
369
370} // namespace art
371
372#endif // ART_COMPILER_UTILS_TEST_DEX_FILE_BUILDER_H_