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