test_dex_file_builder.h revision c91df2d6339dd4adf2da582372451df19ce2ff44
1/* 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_ 373