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