1 /*
2  * Copyright (C) 2017 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  * Implementation file of dex ir verifier.
17  *
18  * Compares two dex files at the IR level, allowing differences in layout, but not in data.
19  */
20 
21 #include "dex_verify.h"
22 
23 #include <inttypes.h>
24 
25 #include "android-base/stringprintf.h"
26 
27 namespace art {
28 
29 using android::base::StringPrintf;
30 
VerifyOutputDexFile(dex_ir::Header * orig_header,dex_ir::Header * output_header,std::string * error_msg)31 bool VerifyOutputDexFile(dex_ir::Header* orig_header,
32                          dex_ir::Header* output_header,
33                          std::string* error_msg) {
34   dex_ir::Collections& orig = orig_header->GetCollections();
35   dex_ir::Collections& output = output_header->GetCollections();
36 
37   // Compare all id sections. They have a defined order that can't be changed by dexlayout.
38   if (!VerifyIds(orig.StringIds(), output.StringIds(), "string ids", error_msg) ||
39       !VerifyIds(orig.TypeIds(), output.TypeIds(), "type ids", error_msg) ||
40       !VerifyIds(orig.ProtoIds(), output.ProtoIds(), "proto ids", error_msg) ||
41       !VerifyIds(orig.FieldIds(), output.FieldIds(), "field ids", error_msg) ||
42       !VerifyIds(orig.MethodIds(), output.MethodIds(), "method ids", error_msg)) {
43     return false;
44   }
45   // Compare class defs. The order may have been changed by dexlayout.
46   if (!VerifyClassDefs(orig.ClassDefs(), output.ClassDefs(), error_msg)) {
47     return false;
48   }
49   return true;
50 }
51 
VerifyIds(std::vector<std::unique_ptr<T>> & orig,std::vector<std::unique_ptr<T>> & output,const char * section_name,std::string * error_msg)52 template<class T> bool VerifyIds(std::vector<std::unique_ptr<T>>& orig,
53                                  std::vector<std::unique_ptr<T>>& output,
54                                  const char* section_name,
55                                  std::string* error_msg) {
56   if (orig.size() != output.size()) {
57     *error_msg = StringPrintf(
58         "Mismatched size for %s section: %zu vs %zu.", section_name, orig.size(), output.size());
59     return false;
60   }
61   for (size_t i = 0; i < orig.size(); ++i) {
62     if (!VerifyId(orig[i].get(), output[i].get(), error_msg)) {
63       return false;
64     }
65   }
66   return true;
67 }
68 
VerifyId(dex_ir::StringId * orig,dex_ir::StringId * output,std::string * error_msg)69 bool VerifyId(dex_ir::StringId* orig, dex_ir::StringId* output, std::string* error_msg) {
70   if (strcmp(orig->Data(), output->Data()) != 0) {
71     *error_msg = StringPrintf("Mismatched string data for string id %u at offset %x: %s vs %s.",
72                               orig->GetIndex(),
73                               orig->GetOffset(),
74                               orig->Data(),
75                               output->Data());
76     return false;
77   }
78   return true;
79 }
80 
VerifyId(dex_ir::TypeId * orig,dex_ir::TypeId * output,std::string * error_msg)81 bool VerifyId(dex_ir::TypeId* orig, dex_ir::TypeId* output, std::string* error_msg) {
82   if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
83     *error_msg = StringPrintf("Mismatched string index for type id %u at offset %x: %u vs %u.",
84                               orig->GetIndex(),
85                               orig->GetOffset(),
86                               orig->GetStringId()->GetIndex(),
87                               output->GetStringId()->GetIndex());
88     return false;
89   }
90   return true;
91 }
92 
VerifyId(dex_ir::ProtoId * orig,dex_ir::ProtoId * output,std::string * error_msg)93 bool VerifyId(dex_ir::ProtoId* orig, dex_ir::ProtoId* output, std::string* error_msg) {
94   if (orig->Shorty()->GetIndex() != output->Shorty()->GetIndex()) {
95     *error_msg = StringPrintf("Mismatched string index for proto id %u at offset %x: %u vs %u.",
96                               orig->GetIndex(),
97                               orig->GetOffset(),
98                               orig->Shorty()->GetIndex(),
99                               output->Shorty()->GetIndex());
100     return false;
101   }
102   if (orig->ReturnType()->GetIndex() != output->ReturnType()->GetIndex()) {
103     *error_msg = StringPrintf("Mismatched type index for proto id %u at offset %x: %u vs %u.",
104                               orig->GetIndex(),
105                               orig->GetOffset(),
106                               orig->ReturnType()->GetIndex(),
107                               output->ReturnType()->GetIndex());
108     return false;
109   }
110   if (!VerifyTypeList(orig->Parameters(), output->Parameters())) {
111     *error_msg = StringPrintf("Mismatched type list for proto id %u at offset %x.",
112                               orig->GetIndex(),
113                               orig->GetOffset());
114   }
115   return true;
116 }
117 
VerifyId(dex_ir::FieldId * orig,dex_ir::FieldId * output,std::string * error_msg)118 bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg) {
119   if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
120     *error_msg =
121         StringPrintf("Mismatched class type index for field id %u at offset %x: %u vs %u.",
122                      orig->GetIndex(),
123                      orig->GetOffset(),
124                      orig->Class()->GetIndex(),
125                      output->Class()->GetIndex());
126     return false;
127   }
128   if (orig->Type()->GetIndex() != output->Type()->GetIndex()) {
129     *error_msg = StringPrintf("Mismatched type index for field id %u at offset %x: %u vs %u.",
130                               orig->GetIndex(),
131                               orig->GetOffset(),
132                               orig->Class()->GetIndex(),
133                               output->Class()->GetIndex());
134     return false;
135   }
136   if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
137     *error_msg = StringPrintf("Mismatched string index for field id %u at offset %x: %u vs %u.",
138                               orig->GetIndex(),
139                               orig->GetOffset(),
140                               orig->Name()->GetIndex(),
141                               output->Name()->GetIndex());
142     return false;
143   }
144   return true;
145 }
146 
VerifyId(dex_ir::MethodId * orig,dex_ir::MethodId * output,std::string * error_msg)147 bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg) {
148   if (orig->Class()->GetIndex() != output->Class()->GetIndex()) {
149     *error_msg = StringPrintf("Mismatched type index for method id %u at offset %x: %u vs %u.",
150                               orig->GetIndex(),
151                               orig->GetOffset(),
152                               orig->Class()->GetIndex(),
153                               output->Class()->GetIndex());
154     return false;
155   }
156   if (orig->Proto()->GetIndex() != output->Proto()->GetIndex()) {
157     *error_msg = StringPrintf("Mismatched proto index for method id %u at offset %x: %u vs %u.",
158                               orig->GetIndex(),
159                               orig->GetOffset(),
160                               orig->Class()->GetIndex(),
161                               output->Class()->GetIndex());
162     return false;
163   }
164   if (orig->Name()->GetIndex() != output->Name()->GetIndex()) {
165     *error_msg =
166         StringPrintf("Mismatched string index for method id %u at offset %x: %u vs %u.",
167                      orig->GetIndex(),
168                      orig->GetOffset(),
169                      orig->Name()->GetIndex(),
170                      output->Name()->GetIndex());
171     return false;
172   }
173   return true;
174 }
175 
176 struct ClassDefCompare {
operator ()art::ClassDefCompare177   bool operator()(dex_ir::ClassDef* lhs, dex_ir::ClassDef* rhs) const {
178     return lhs->ClassType()->GetIndex() < rhs->ClassType()->GetIndex();
179   }
180 };
181 
182 // The class defs may have a new order due to dexlayout. Use the class's class_idx to uniquely
183 // identify them and sort them for comparison.
VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>> & orig,std::vector<std::unique_ptr<dex_ir::ClassDef>> & output,std::string * error_msg)184 bool VerifyClassDefs(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
185                      std::vector<std::unique_ptr<dex_ir::ClassDef>>& output,
186                      std::string* error_msg) {
187   if (orig.size() != output.size()) {
188     *error_msg = StringPrintf(
189         "Mismatched size for class defs section: %zu vs %zu.", orig.size(), output.size());
190     return false;
191   }
192   // Store the class defs into sets sorted by the class's type index.
193   std::set<dex_ir::ClassDef*, ClassDefCompare> orig_set;
194   std::set<dex_ir::ClassDef*, ClassDefCompare> output_set;
195   for (size_t i = 0; i < orig.size(); ++i) {
196     orig_set.insert(orig[i].get());
197     output_set.insert(output[i].get());
198   }
199   auto orig_iter = orig_set.begin();
200   auto output_iter = output_set.begin();
201   while (orig_iter != orig_set.end() && output_iter != output_set.end()) {
202     if (!VerifyClassDef(*orig_iter, *output_iter, error_msg)) {
203       return false;
204     }
205     orig_iter++;
206     output_iter++;
207   }
208   return true;
209 }
210 
VerifyClassDef(dex_ir::ClassDef * orig,dex_ir::ClassDef * output,std::string * error_msg)211 bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg) {
212   if (orig->ClassType()->GetIndex() != output->ClassType()->GetIndex()) {
213     *error_msg =
214         StringPrintf("Mismatched class type index for class def %u at offset %x: %u vs %u.",
215                      orig->GetIndex(),
216                      orig->GetOffset(),
217                      orig->ClassType()->GetIndex(),
218                      output->ClassType()->GetIndex());
219     return false;
220   }
221   if (orig->GetAccessFlags() != output->GetAccessFlags()) {
222     *error_msg =
223         StringPrintf("Mismatched access flags for class def %u at offset %x: %x vs %x.",
224                      orig->GetIndex(),
225                      orig->GetOffset(),
226                      orig->GetAccessFlags(),
227                      output->GetAccessFlags());
228     return false;
229   }
230   uint32_t orig_super = orig->Superclass() == nullptr ? 0 : orig->Superclass()->GetIndex();
231   uint32_t output_super = output->Superclass() == nullptr ? 0 : output->Superclass()->GetIndex();
232   if (orig_super != output_super) {
233     *error_msg =
234         StringPrintf("Mismatched super class for class def %u at offset %x: %u vs %u.",
235                      orig->GetIndex(),
236                      orig->GetOffset(),
237                      orig_super,
238                      output_super);
239     return false;
240   }
241   if (!VerifyTypeList(orig->Interfaces(), output->Interfaces())) {
242     *error_msg = StringPrintf("Mismatched type list for class def %u at offset %x.",
243                               orig->GetIndex(),
244                               orig->GetOffset());
245     return false;
246   }
247   const char* orig_source = orig->SourceFile() == nullptr ? "" : orig->SourceFile()->Data();
248   const char* output_source = output->SourceFile() == nullptr ? "" : output->SourceFile()->Data();
249   if (strcmp(orig_source, output_source) != 0) {
250     *error_msg = StringPrintf("Mismatched source file for class def %u at offset %x: %s vs %s.",
251                               orig->GetIndex(),
252                               orig->GetOffset(),
253                               orig_source,
254                               output_source);
255     return false;
256   }
257   if (!VerifyAnnotationsDirectory(orig->Annotations(), output->Annotations(), error_msg)) {
258     return false;
259   }
260   if (!VerifyClassData(orig->GetClassData(), output->GetClassData(), error_msg)) {
261     return false;
262   }
263   return VerifyEncodedArray(orig->StaticValues(), output->StaticValues(), error_msg);
264 }
265 
VerifyTypeList(const dex_ir::TypeList * orig,const dex_ir::TypeList * output)266 bool VerifyTypeList(const dex_ir::TypeList* orig, const dex_ir::TypeList* output) {
267   if (orig == nullptr || output == nullptr) {
268     return orig == output;
269   }
270   const dex_ir::TypeIdVector* orig_list = orig->GetTypeList();
271   const dex_ir::TypeIdVector* output_list = output->GetTypeList();
272   if (orig_list->size() != output_list->size()) {
273     return false;
274   }
275   for (size_t i = 0; i < orig_list->size(); ++i) {
276     if ((*orig_list)[i]->GetIndex() != (*output_list)[i]->GetIndex()) {
277       return false;
278     }
279   }
280   return true;
281 }
282 
VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem * orig,dex_ir::AnnotationsDirectoryItem * output,std::string * error_msg)283 bool VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem* orig,
284                                 dex_ir::AnnotationsDirectoryItem* output,
285                                 std::string* error_msg) {
286   if (orig == nullptr || output == nullptr) {
287     if (orig != output) {
288       *error_msg = "Found unexpected empty annotations directory.";
289       return false;
290     }
291     return true;
292   }
293   if (!VerifyAnnotationSet(orig->GetClassAnnotation(), output->GetClassAnnotation(), error_msg)) {
294     return false;
295   }
296   if (!VerifyFieldAnnotations(orig->GetFieldAnnotations(),
297                               output->GetFieldAnnotations(),
298                               orig->GetOffset(),
299                               error_msg)) {
300     return false;
301   }
302   if (!VerifyMethodAnnotations(orig->GetMethodAnnotations(),
303                                output->GetMethodAnnotations(),
304                                orig->GetOffset(),
305                                error_msg)) {
306     return false;
307   }
308   return VerifyParameterAnnotations(orig->GetParameterAnnotations(),
309                                     output->GetParameterAnnotations(),
310                                     orig->GetOffset(),
311                                     error_msg);
312 }
313 
VerifyFieldAnnotations(dex_ir::FieldAnnotationVector * orig,dex_ir::FieldAnnotationVector * output,uint32_t orig_offset,std::string * error_msg)314 bool VerifyFieldAnnotations(dex_ir::FieldAnnotationVector* orig,
315                             dex_ir::FieldAnnotationVector* output,
316                             uint32_t orig_offset,
317                             std::string* error_msg) {
318   if (orig == nullptr || output == nullptr) {
319     if (orig != output) {
320       *error_msg = StringPrintf(
321           "Found unexpected empty field annotations for annotations directory at offset %x.",
322           orig_offset);
323       return false;
324     }
325     return true;
326   }
327   if (orig->size() != output->size()) {
328     *error_msg = StringPrintf(
329         "Mismatched field annotations size for annotations directory at offset %x: %zu vs %zu.",
330         orig_offset,
331         orig->size(),
332         output->size());
333     return false;
334   }
335   for (size_t i = 0; i < orig->size(); ++i) {
336     dex_ir::FieldAnnotation* orig_field = (*orig)[i].get();
337     dex_ir::FieldAnnotation* output_field = (*output)[i].get();
338     if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
339       *error_msg = StringPrintf(
340           "Mismatched field annotation index for annotations directory at offset %x: %u vs %u.",
341           orig_offset,
342           orig_field->GetFieldId()->GetIndex(),
343           output_field->GetFieldId()->GetIndex());
344       return false;
345     }
346     if (!VerifyAnnotationSet(orig_field->GetAnnotationSetItem(),
347                              output_field->GetAnnotationSetItem(),
348                              error_msg)) {
349       return false;
350     }
351   }
352   return true;
353 }
354 
VerifyMethodAnnotations(dex_ir::MethodAnnotationVector * orig,dex_ir::MethodAnnotationVector * output,uint32_t orig_offset,std::string * error_msg)355 bool VerifyMethodAnnotations(dex_ir::MethodAnnotationVector* orig,
356                              dex_ir::MethodAnnotationVector* output,
357                              uint32_t orig_offset,
358                              std::string* error_msg) {
359   if (orig == nullptr || output == nullptr) {
360     if (orig != output) {
361       *error_msg = StringPrintf(
362           "Found unexpected empty method annotations for annotations directory at offset %x.",
363           orig_offset);
364       return false;
365     }
366     return true;
367   }
368   if (orig->size() != output->size()) {
369     *error_msg = StringPrintf(
370         "Mismatched method annotations size for annotations directory at offset %x: %zu vs %zu.",
371         orig_offset,
372         orig->size(),
373         output->size());
374     return false;
375   }
376   for (size_t i = 0; i < orig->size(); ++i) {
377     dex_ir::MethodAnnotation* orig_method = (*orig)[i].get();
378     dex_ir::MethodAnnotation* output_method = (*output)[i].get();
379     if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
380       *error_msg = StringPrintf(
381           "Mismatched method annotation index for annotations directory at offset %x: %u vs %u.",
382           orig_offset,
383           orig_method->GetMethodId()->GetIndex(),
384           output_method->GetMethodId()->GetIndex());
385       return false;
386     }
387     if (!VerifyAnnotationSet(orig_method->GetAnnotationSetItem(),
388                              output_method->GetAnnotationSetItem(),
389                              error_msg)) {
390       return false;
391     }
392   }
393   return true;
394 }
395 
VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector * orig,dex_ir::ParameterAnnotationVector * output,uint32_t orig_offset,std::string * error_msg)396 bool VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector* orig,
397                                 dex_ir::ParameterAnnotationVector* output,
398                                 uint32_t orig_offset,
399                                 std::string* error_msg) {
400   if (orig == nullptr || output == nullptr) {
401     if (orig != output) {
402       *error_msg = StringPrintf(
403           "Found unexpected empty parameter annotations for annotations directory at offset %x.",
404           orig_offset);
405       return false;
406     }
407     return true;
408   }
409   if (orig->size() != output->size()) {
410     *error_msg = StringPrintf(
411         "Mismatched parameter annotations size for annotations directory at offset %x: %zu vs %zu.",
412         orig_offset,
413         orig->size(),
414         output->size());
415     return false;
416   }
417   for (size_t i = 0; i < orig->size(); ++i) {
418     dex_ir::ParameterAnnotation* orig_param = (*orig)[i].get();
419     dex_ir::ParameterAnnotation* output_param = (*output)[i].get();
420     if (orig_param->GetMethodId()->GetIndex() != output_param->GetMethodId()->GetIndex()) {
421       *error_msg = StringPrintf(
422           "Mismatched parameter annotation index for annotations directory at offset %x: %u vs %u.",
423           orig_offset,
424           orig_param->GetMethodId()->GetIndex(),
425           output_param->GetMethodId()->GetIndex());
426       return false;
427     }
428     if (!VerifyAnnotationSetRefList(orig_param->GetAnnotations(),
429                                     output_param->GetAnnotations(),
430                                     error_msg)) {
431       return false;
432     }
433   }
434   return true;
435 }
436 
VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList * orig,dex_ir::AnnotationSetRefList * output,std::string * error_msg)437 bool VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList* orig,
438                                 dex_ir::AnnotationSetRefList* output,
439                                 std::string* error_msg) {
440   std::vector<dex_ir::AnnotationSetItem*>* orig_items = orig->GetItems();
441   std::vector<dex_ir::AnnotationSetItem*>* output_items = output->GetItems();
442   if (orig_items->size() != output_items->size()) {
443     *error_msg = StringPrintf(
444         "Mismatched annotation set ref list size at offset %x: %zu vs %zu.",
445         orig->GetOffset(),
446         orig_items->size(),
447         output_items->size());
448     return false;
449   }
450   for (size_t i = 0; i < orig_items->size(); ++i) {
451     if (!VerifyAnnotationSet((*orig_items)[i], (*output_items)[i], error_msg)) {
452       return false;
453     }
454   }
455   return true;
456 }
457 
VerifyAnnotationSet(dex_ir::AnnotationSetItem * orig,dex_ir::AnnotationSetItem * output,std::string * error_msg)458 bool VerifyAnnotationSet(dex_ir::AnnotationSetItem* orig,
459                          dex_ir::AnnotationSetItem* output,
460                          std::string* error_msg) {
461   if (orig == nullptr || output == nullptr) {
462     if (orig != output) {
463       *error_msg = "Found unexpected empty annotation set.";
464       return false;
465     }
466     return true;
467   }
468   std::vector<dex_ir::AnnotationItem*>* orig_items = orig->GetItems();
469   std::vector<dex_ir::AnnotationItem*>* output_items = output->GetItems();
470   if (orig_items->size() != output_items->size()) {
471     *error_msg = StringPrintf("Mismatched size for annotation set at offset %x: %zu vs %zu.",
472                               orig->GetOffset(),
473                               orig_items->size(),
474                               output_items->size());
475     return false;
476   }
477   for (size_t i = 0; i < orig_items->size(); ++i) {
478     if (!VerifyAnnotation((*orig_items)[i], (*output_items)[i], error_msg)) {
479       return false;
480     }
481   }
482   return true;
483 }
484 
VerifyAnnotation(dex_ir::AnnotationItem * orig,dex_ir::AnnotationItem * output,std::string * error_msg)485 bool VerifyAnnotation(dex_ir::AnnotationItem* orig,
486                       dex_ir::AnnotationItem* output,
487                       std::string* error_msg) {
488   if (orig->GetVisibility() != output->GetVisibility()) {
489     *error_msg = StringPrintf("Mismatched visibility for annotation at offset %x: %u vs %u.",
490                               orig->GetOffset(),
491                               orig->GetVisibility(),
492                               output->GetVisibility());
493     return false;
494   }
495   return VerifyEncodedAnnotation(orig->GetAnnotation(),
496                                  output->GetAnnotation(),
497                                  orig->GetOffset(),
498                                  error_msg);
499 }
500 
VerifyEncodedAnnotation(dex_ir::EncodedAnnotation * orig,dex_ir::EncodedAnnotation * output,uint32_t orig_offset,std::string * error_msg)501 bool VerifyEncodedAnnotation(dex_ir::EncodedAnnotation* orig,
502                              dex_ir::EncodedAnnotation* output,
503                              uint32_t orig_offset,
504                              std::string* error_msg) {
505   if (orig->GetType()->GetIndex() != output->GetType()->GetIndex()) {
506     *error_msg = StringPrintf(
507         "Mismatched encoded annotation type for annotation at offset %x: %u vs %u.",
508         orig_offset,
509         orig->GetType()->GetIndex(),
510         output->GetType()->GetIndex());
511     return false;
512   }
513   dex_ir::AnnotationElementVector* orig_elements = orig->GetAnnotationElements();
514   dex_ir::AnnotationElementVector* output_elements = output->GetAnnotationElements();
515   if (orig_elements->size() != output_elements->size()) {
516     *error_msg = StringPrintf(
517         "Mismatched encoded annotation size for annotation at offset %x: %zu vs %zu.",
518         orig_offset,
519         orig_elements->size(),
520         output_elements->size());
521     return false;
522   }
523   for (size_t i = 0; i < orig_elements->size(); ++i) {
524     if (!VerifyAnnotationElement((*orig_elements)[i].get(),
525                                  (*output_elements)[i].get(),
526                                  orig_offset,
527                                  error_msg)) {
528       return false;
529     }
530   }
531   return true;
532 }
533 
VerifyAnnotationElement(dex_ir::AnnotationElement * orig,dex_ir::AnnotationElement * output,uint32_t orig_offset,std::string * error_msg)534 bool VerifyAnnotationElement(dex_ir::AnnotationElement* orig,
535                              dex_ir::AnnotationElement* output,
536                              uint32_t orig_offset,
537                              std::string* error_msg) {
538   if (orig->GetName()->GetIndex() != output->GetName()->GetIndex()) {
539     *error_msg = StringPrintf(
540         "Mismatched annotation element name for annotation at offset %x: %u vs %u.",
541         orig_offset,
542         orig->GetName()->GetIndex(),
543         output->GetName()->GetIndex());
544     return false;
545   }
546   return VerifyEncodedValue(orig->GetValue(), output->GetValue(), orig_offset, error_msg);
547 }
548 
VerifyEncodedValue(dex_ir::EncodedValue * orig,dex_ir::EncodedValue * output,uint32_t orig_offset,std::string * error_msg)549 bool VerifyEncodedValue(dex_ir::EncodedValue* orig,
550                         dex_ir::EncodedValue* output,
551                         uint32_t orig_offset,
552                         std::string* error_msg) {
553   if (orig->Type() != output->Type()) {
554     *error_msg = StringPrintf(
555         "Mismatched encoded value type for annotation or encoded array at offset %x: %d vs %d.",
556         orig_offset,
557         orig->Type(),
558         output->Type());
559     return false;
560   }
561   switch (orig->Type()) {
562     case DexFile::kDexAnnotationByte:
563       if (orig->GetByte() != output->GetByte()) {
564         *error_msg = StringPrintf("Mismatched encoded byte for annotation at offset %x: %d vs %d.",
565                                   orig_offset,
566                                   orig->GetByte(),
567                                   output->GetByte());
568         return false;
569       }
570       break;
571     case DexFile::kDexAnnotationShort:
572       if (orig->GetShort() != output->GetShort()) {
573         *error_msg = StringPrintf("Mismatched encoded short for annotation at offset %x: %d vs %d.",
574                                   orig_offset,
575                                   orig->GetShort(),
576                                   output->GetShort());
577         return false;
578       }
579       break;
580     case DexFile::kDexAnnotationChar:
581       if (orig->GetChar() != output->GetChar()) {
582         *error_msg = StringPrintf("Mismatched encoded char for annotation at offset %x: %c vs %c.",
583                                   orig_offset,
584                                   orig->GetChar(),
585                                   output->GetChar());
586         return false;
587       }
588       break;
589     case DexFile::kDexAnnotationInt:
590       if (orig->GetInt() != output->GetInt()) {
591         *error_msg = StringPrintf("Mismatched encoded int for annotation at offset %x: %d vs %d.",
592                                   orig_offset,
593                                   orig->GetInt(),
594                                   output->GetInt());
595         return false;
596       }
597       break;
598     case DexFile::kDexAnnotationLong:
599       if (orig->GetLong() != output->GetLong()) {
600         *error_msg = StringPrintf(
601             "Mismatched encoded long for annotation at offset %x: %" PRId64 " vs %" PRId64 ".",
602             orig_offset,
603             orig->GetLong(),
604             output->GetLong());
605         return false;
606       }
607       break;
608     case DexFile::kDexAnnotationFloat:
609       // The float value is encoded, so compare as if it's an int.
610       if (orig->GetInt() != output->GetInt()) {
611         *error_msg = StringPrintf(
612             "Mismatched encoded float for annotation at offset %x: %x (encoded) vs %x (encoded).",
613                                   orig_offset,
614                                   orig->GetInt(),
615                                   output->GetInt());
616         return false;
617       }
618       break;
619     case DexFile::kDexAnnotationDouble:
620       // The double value is encoded, so compare as if it's a long.
621       if (orig->GetLong() != output->GetLong()) {
622         *error_msg = StringPrintf(
623             "Mismatched encoded double for annotation at offset %x: %" PRIx64
624             " (encoded) vs %" PRIx64 " (encoded).",
625             orig_offset,
626             orig->GetLong(),
627             output->GetLong());
628         return false;
629       }
630       break;
631     case DexFile::kDexAnnotationString:
632       if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) {
633         *error_msg = StringPrintf(
634             "Mismatched encoded string for annotation at offset %x: %s vs %s.",
635             orig_offset,
636             orig->GetStringId()->Data(),
637             output->GetStringId()->Data());
638         return false;
639       }
640       break;
641     case DexFile::kDexAnnotationType:
642       if (orig->GetTypeId()->GetIndex() != output->GetTypeId()->GetIndex()) {
643         *error_msg = StringPrintf("Mismatched encoded type for annotation at offset %x: %u vs %u.",
644                                   orig_offset,
645                                   orig->GetTypeId()->GetIndex(),
646                                   output->GetTypeId()->GetIndex());
647         return false;
648       }
649       break;
650     case DexFile::kDexAnnotationField:
651     case DexFile::kDexAnnotationEnum:
652       if (orig->GetFieldId()->GetIndex() != output->GetFieldId()->GetIndex()) {
653         *error_msg = StringPrintf("Mismatched encoded field for annotation at offset %x: %u vs %u.",
654                                   orig_offset,
655                                   orig->GetFieldId()->GetIndex(),
656                                   output->GetFieldId()->GetIndex());
657         return false;
658       }
659       break;
660     case DexFile::kDexAnnotationMethod:
661       if (orig->GetMethodId()->GetIndex() != output->GetMethodId()->GetIndex()) {
662         *error_msg = StringPrintf(
663             "Mismatched encoded method for annotation at offset %x: %u vs %u.",
664             orig_offset,
665             orig->GetMethodId()->GetIndex(),
666             output->GetMethodId()->GetIndex());
667         return false;
668       }
669       break;
670     case DexFile::kDexAnnotationArray:
671       if (!VerifyEncodedArray(orig->GetEncodedArray(), output->GetEncodedArray(), error_msg)) {
672         return false;
673       }
674       break;
675     case DexFile::kDexAnnotationAnnotation:
676       if (!VerifyEncodedAnnotation(orig->GetEncodedAnnotation(),
677                                    output->GetEncodedAnnotation(),
678                                    orig_offset,
679                                    error_msg)) {
680         return false;
681       }
682       break;
683     case DexFile::kDexAnnotationNull:
684       break;
685     case DexFile::kDexAnnotationBoolean:
686       if (orig->GetBoolean() != output->GetBoolean()) {
687         *error_msg = StringPrintf(
688             "Mismatched encoded boolean for annotation at offset %x: %d vs %d.",
689             orig_offset,
690             orig->GetBoolean(),
691             output->GetBoolean());
692         return false;
693       }
694       break;
695     default:
696       break;
697   }
698   return true;
699 }
700 
VerifyEncodedArray(dex_ir::EncodedArrayItem * orig,dex_ir::EncodedArrayItem * output,std::string * error_msg)701 bool VerifyEncodedArray(dex_ir::EncodedArrayItem* orig,
702                         dex_ir::EncodedArrayItem* output,
703                         std::string* error_msg) {
704   if (orig == nullptr || output == nullptr) {
705     if (orig != output) {
706       *error_msg = "Found unexpected empty encoded array.";
707       return false;
708     }
709     return true;
710   }
711   dex_ir::EncodedValueVector* orig_vector = orig->GetEncodedValues();
712   dex_ir::EncodedValueVector* output_vector = output->GetEncodedValues();
713   if (orig_vector->size() != output_vector->size()) {
714     *error_msg = StringPrintf("Mismatched size for encoded array at offset %x: %zu vs %zu.",
715                               orig->GetOffset(),
716                               orig_vector->size(),
717                               output_vector->size());
718     return false;
719   }
720   for (size_t i = 0; i < orig_vector->size(); ++i) {
721     if (!VerifyEncodedValue((*orig_vector)[i].get(),
722                             (*output_vector)[i].get(),
723                             orig->GetOffset(),
724                             error_msg)) {
725       return false;
726     }
727   }
728   return true;
729 }
730 
VerifyClassData(dex_ir::ClassData * orig,dex_ir::ClassData * output,std::string * error_msg)731 bool VerifyClassData(dex_ir::ClassData* orig, dex_ir::ClassData* output, std::string* error_msg) {
732   if (orig == nullptr || output == nullptr) {
733     if (orig != output) {
734       *error_msg = "Found unexpected empty class data.";
735       return false;
736     }
737     return true;
738   }
739   if (!VerifyFields(orig->StaticFields(), output->StaticFields(), orig->GetOffset(), error_msg)) {
740     return false;
741   }
742   if (!VerifyFields(orig->InstanceFields(),
743                     output->InstanceFields(),
744                     orig->GetOffset(),
745                     error_msg)) {
746     return false;
747   }
748   if (!VerifyMethods(orig->DirectMethods(),
749                      output->DirectMethods(),
750                      orig->GetOffset(),
751                      error_msg)) {
752     return false;
753   }
754   return VerifyMethods(orig->VirtualMethods(),
755                        output->VirtualMethods(),
756                        orig->GetOffset(),
757                        error_msg);
758 }
759 
VerifyFields(dex_ir::FieldItemVector * orig,dex_ir::FieldItemVector * output,uint32_t orig_offset,std::string * error_msg)760 bool VerifyFields(dex_ir::FieldItemVector* orig,
761                   dex_ir::FieldItemVector* output,
762                   uint32_t orig_offset,
763                   std::string* error_msg) {
764   if (orig->size() != output->size()) {
765     *error_msg = StringPrintf("Mismatched fields size for class data at offset %x: %zu vs %zu.",
766                               orig_offset,
767                               orig->size(),
768                               output->size());
769     return false;
770   }
771   for (size_t i = 0; i < orig->size(); ++i) {
772     dex_ir::FieldItem* orig_field = (*orig)[i].get();
773     dex_ir::FieldItem* output_field = (*output)[i].get();
774     if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) {
775       *error_msg = StringPrintf("Mismatched field index for class data at offset %x: %u vs %u.",
776                                 orig_offset,
777                                 orig_field->GetFieldId()->GetIndex(),
778                                 output_field->GetFieldId()->GetIndex());
779       return false;
780     }
781     if (orig_field->GetAccessFlags() != output_field->GetAccessFlags()) {
782       *error_msg = StringPrintf(
783           "Mismatched field access flags for class data at offset %x: %u vs %u.",
784           orig_offset,
785           orig_field->GetAccessFlags(),
786           output_field->GetAccessFlags());
787       return false;
788     }
789   }
790   return true;
791 }
792 
VerifyMethods(dex_ir::MethodItemVector * orig,dex_ir::MethodItemVector * output,uint32_t orig_offset,std::string * error_msg)793 bool VerifyMethods(dex_ir::MethodItemVector* orig,
794                    dex_ir::MethodItemVector* output,
795                    uint32_t orig_offset,
796                    std::string* error_msg) {
797   if (orig->size() != output->size()) {
798     *error_msg = StringPrintf("Mismatched methods size for class data at offset %x: %zu vs %zu.",
799                               orig_offset,
800                               orig->size(),
801                               output->size());
802     return false;
803   }
804   for (size_t i = 0; i < orig->size(); ++i) {
805     dex_ir::MethodItem* orig_method = (*orig)[i].get();
806     dex_ir::MethodItem* output_method = (*output)[i].get();
807     if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) {
808       *error_msg = StringPrintf("Mismatched method index for class data at offset %x: %u vs %u.",
809                                 orig_offset,
810                                 orig_method->GetMethodId()->GetIndex(),
811                                 output_method->GetMethodId()->GetIndex());
812       return false;
813     }
814     if (orig_method->GetAccessFlags() != output_method->GetAccessFlags()) {
815       *error_msg = StringPrintf(
816           "Mismatched method access flags for class data at offset %x: %u vs %u.",
817           orig_offset,
818           orig_method->GetAccessFlags(),
819           output_method->GetAccessFlags());
820       return false;
821     }
822     if (!VerifyCode(orig_method->GetCodeItem(), output_method->GetCodeItem(), error_msg)) {
823       return false;
824     }
825   }
826   return true;
827 }
828 
VerifyCode(dex_ir::CodeItem * orig,dex_ir::CodeItem * output,std::string * error_msg)829 bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* error_msg) {
830   if (orig == nullptr || output == nullptr) {
831     if (orig != output) {
832       *error_msg = "Found unexpected empty code item.";
833       return false;
834     }
835     return true;
836   }
837   if (orig->RegistersSize() != output->RegistersSize()) {
838     *error_msg = StringPrintf("Mismatched registers size for code item at offset %x: %u vs %u.",
839                               orig->GetOffset(),
840                               orig->RegistersSize(),
841                               output->RegistersSize());
842     return false;
843   }
844   if (orig->InsSize() != output->InsSize()) {
845     *error_msg = StringPrintf("Mismatched ins size for code item at offset %x: %u vs %u.",
846                               orig->GetOffset(),
847                               orig->InsSize(),
848                               output->InsSize());
849     return false;
850   }
851   if (orig->OutsSize() != output->OutsSize()) {
852     *error_msg = StringPrintf("Mismatched outs size for code item at offset %x: %u vs %u.",
853                               orig->GetOffset(),
854                               orig->OutsSize(),
855                               output->OutsSize());
856     return false;
857   }
858   if (orig->TriesSize() != output->TriesSize()) {
859     *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %u vs %u.",
860                               orig->GetOffset(),
861                               orig->TriesSize(),
862                               output->TriesSize());
863     return false;
864   }
865   if (!VerifyDebugInfo(orig->DebugInfo(), output->DebugInfo(), error_msg)) {
866     return false;
867   }
868   if (orig->InsnsSize() != output->InsnsSize()) {
869     *error_msg = StringPrintf("Mismatched insns size for code item at offset %x: %u vs %u.",
870                               orig->GetOffset(),
871                               orig->InsnsSize(),
872                               output->InsnsSize());
873     return false;
874   }
875   if (memcmp(orig->Insns(), output->Insns(), orig->InsnsSize()) != 0) {
876     *error_msg = StringPrintf("Mismatched insns for code item at offset %x.",
877                               orig->GetOffset());
878     return false;
879   }
880   if (!VerifyTries(orig->Tries(), output->Tries(), orig->GetOffset(), error_msg)) {
881     return false;
882   }
883   return VerifyHandlers(orig->Handlers(), output->Handlers(), orig->GetOffset(), error_msg);
884 }
885 
VerifyDebugInfo(dex_ir::DebugInfoItem * orig,dex_ir::DebugInfoItem * output,std::string * error_msg)886 bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig,
887                      dex_ir::DebugInfoItem* output,
888                      std::string* error_msg) {
889   if (orig == nullptr || output == nullptr) {
890     if (orig != output) {
891       *error_msg = "Found unexpected empty debug info.";
892       return false;
893     }
894     return true;
895   }
896   if (!VerifyPositionInfo(orig->GetPositionInfo(),
897                           output->GetPositionInfo(),
898                           orig->GetOffset(),
899                           error_msg)) {
900     return false;
901   }
902   return VerifyLocalInfo(orig->GetLocalInfo(),
903                          output->GetLocalInfo(),
904                          orig->GetOffset(),
905                          error_msg);
906 }
907 
VerifyPositionInfo(dex_ir::PositionInfoVector & orig,dex_ir::PositionInfoVector & output,uint32_t orig_offset,std::string * error_msg)908 bool VerifyPositionInfo(dex_ir::PositionInfoVector& orig,
909                         dex_ir::PositionInfoVector& output,
910                         uint32_t orig_offset,
911                         std::string* error_msg) {
912   if (orig.size() != output.size()) {
913     *error_msg = StringPrintf(
914         "Mismatched number of positions for debug info at offset %x: %zu vs %zu.",
915         orig_offset,
916         orig.size(),
917         output.size());
918     return false;
919   }
920   for (size_t i = 0; i < orig.size(); ++i) {
921     if (orig[i]->address_ != output[i]->address_) {
922       *error_msg = StringPrintf(
923           "Mismatched position address for debug info at offset %x: %u vs %u.",
924           orig_offset,
925           orig[i]->address_,
926           output[i]->address_);
927       return false;
928     }
929     if (orig[i]->line_ != output[i]->line_) {
930       *error_msg = StringPrintf("Mismatched position line for debug info at offset %x: %u vs %u.",
931                                 orig_offset,
932                                 orig[i]->line_,
933                                 output[i]->line_);
934       return false;
935     }
936   }
937   return true;
938 }
939 
VerifyLocalInfo(dex_ir::LocalInfoVector & orig,dex_ir::LocalInfoVector & output,uint32_t orig_offset,std::string * error_msg)940 bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig,
941                      dex_ir::LocalInfoVector& output,
942                      uint32_t orig_offset,
943                      std::string* error_msg) {
944   if (orig.size() != output.size()) {
945     *error_msg = StringPrintf(
946         "Mismatched number of locals for debug info at offset %x: %zu vs %zu.",
947         orig_offset,
948         orig.size(),
949         output.size());
950     return false;
951   }
952   for (size_t i = 0; i < orig.size(); ++i) {
953     if (orig[i]->name_ != output[i]->name_) {
954       *error_msg = StringPrintf("Mismatched local name for debug info at offset %x: %s vs %s.",
955                                 orig_offset,
956                                 orig[i]->name_.c_str(),
957                                 output[i]->name_.c_str());
958       return false;
959     }
960     if (orig[i]->descriptor_ != output[i]->descriptor_) {
961       *error_msg = StringPrintf(
962           "Mismatched local descriptor for debug info at offset %x: %s vs %s.",
963           orig_offset,
964           orig[i]->descriptor_.c_str(),
965           output[i]->descriptor_.c_str());
966       return false;
967     }
968     if (orig[i]->signature_ != output[i]->signature_) {
969       *error_msg = StringPrintf("Mismatched local signature for debug info at offset %x: %s vs %s.",
970                                 orig_offset,
971                                 orig[i]->signature_.c_str(),
972                                 output[i]->signature_.c_str());
973       return false;
974     }
975     if (orig[i]->start_address_ != output[i]->start_address_) {
976       *error_msg = StringPrintf(
977           "Mismatched local start address for debug info at offset %x: %u vs %u.",
978           orig_offset,
979           orig[i]->start_address_,
980           output[i]->start_address_);
981       return false;
982     }
983     if (orig[i]->end_address_ != output[i]->end_address_) {
984       *error_msg = StringPrintf(
985           "Mismatched local end address for debug info at offset %x: %u vs %u.",
986           orig_offset,
987           orig[i]->end_address_,
988           output[i]->end_address_);
989       return false;
990     }
991     if (orig[i]->reg_ != output[i]->reg_) {
992       *error_msg = StringPrintf("Mismatched local reg for debug info at offset %x: %u vs %u.",
993                                 orig_offset,
994                                 orig[i]->reg_,
995                                 output[i]->reg_);
996       return false;
997     }
998   }
999   return true;
1000 }
1001 
VerifyTries(dex_ir::TryItemVector * orig,dex_ir::TryItemVector * output,uint32_t orig_offset,std::string * error_msg)1002 bool VerifyTries(dex_ir::TryItemVector* orig,
1003                  dex_ir::TryItemVector* output,
1004                  uint32_t orig_offset,
1005                  std::string* error_msg) {
1006   if (orig == nullptr || output == nullptr) {
1007     if (orig != output) {
1008       *error_msg = "Found unexpected empty try items.";
1009       return false;
1010     }
1011     return true;
1012   }
1013   if (orig->size() != output->size()) {
1014     *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %zu vs %zu.",
1015                               orig_offset,
1016                               orig->size(),
1017                               output->size());
1018     return false;
1019   }
1020   for (size_t i = 0; i < orig->size(); ++i) {
1021     const dex_ir::TryItem* orig_try = (*orig)[i].get();
1022     const dex_ir::TryItem* output_try = (*output)[i].get();
1023     if (orig_try->StartAddr() != output_try->StartAddr()) {
1024       *error_msg = StringPrintf(
1025           "Mismatched try item start addr for code item at offset %x: %u vs %u.",
1026           orig_offset,
1027           orig_try->StartAddr(),
1028           output_try->StartAddr());
1029       return false;
1030     }
1031     if (orig_try->InsnCount() != output_try->InsnCount()) {
1032       *error_msg = StringPrintf(
1033           "Mismatched try item insn count for code item at offset %x: %u vs %u.",
1034           orig_offset,
1035           orig_try->InsnCount(),
1036                                 output_try->InsnCount());
1037       return false;
1038     }
1039     if (!VerifyHandler(orig_try->GetHandlers(),
1040                        output_try->GetHandlers(),
1041                        orig_offset,
1042                        error_msg)) {
1043       return false;
1044     }
1045   }
1046   return true;
1047 }
1048 
VerifyHandlers(dex_ir::CatchHandlerVector * orig,dex_ir::CatchHandlerVector * output,uint32_t orig_offset,std::string * error_msg)1049 bool VerifyHandlers(dex_ir::CatchHandlerVector* orig,
1050                     dex_ir::CatchHandlerVector* output,
1051                     uint32_t orig_offset,
1052                     std::string* error_msg) {
1053   if (orig == nullptr || output == nullptr) {
1054     if (orig != output) {
1055       *error_msg = "Found unexpected empty catch handlers.";
1056       return false;
1057     }
1058     return true;
1059   }
1060   if (orig->size() != output->size()) {
1061     *error_msg = StringPrintf(
1062         "Mismatched catch handlers size for code item at offset %x: %zu vs %zu.",
1063         orig_offset,
1064         orig->size(),
1065         output->size());
1066     return false;
1067   }
1068   for (size_t i = 0; i < orig->size(); ++i) {
1069     if (!VerifyHandler((*orig)[i].get(), (*output)[i].get(), orig_offset, error_msg)) {
1070       return false;
1071     }
1072   }
1073   return true;
1074 }
1075 
VerifyHandler(const dex_ir::CatchHandler * orig,const dex_ir::CatchHandler * output,uint32_t orig_offset,std::string * error_msg)1076 bool VerifyHandler(const dex_ir::CatchHandler* orig,
1077                    const dex_ir::CatchHandler* output,
1078                    uint32_t orig_offset,
1079                    std::string* error_msg) {
1080   dex_ir::TypeAddrPairVector* orig_handlers = orig->GetHandlers();
1081   dex_ir::TypeAddrPairVector* output_handlers = output->GetHandlers();
1082   if (orig_handlers->size() != output_handlers->size()) {
1083     *error_msg = StringPrintf(
1084         "Mismatched number of catch handlers for code item at offset %x: %zu vs %zu.",
1085         orig_offset,
1086         orig_handlers->size(),
1087         output_handlers->size());
1088     return false;
1089   }
1090   for (size_t i = 0; i < orig_handlers->size(); ++i) {
1091     const dex_ir::TypeAddrPair* orig_handler = (*orig_handlers)[i].get();
1092     const dex_ir::TypeAddrPair* output_handler = (*output_handlers)[i].get();
1093     if (orig_handler->GetTypeId() == nullptr || output_handler->GetTypeId() == nullptr) {
1094       if (orig_handler->GetTypeId() != output_handler->GetTypeId()) {
1095         *error_msg = StringPrintf(
1096             "Found unexpected catch all catch handler for code item at offset %x.",
1097             orig_offset);
1098         return false;
1099       }
1100     } else if (orig_handler->GetTypeId()->GetIndex() != output_handler->GetTypeId()->GetIndex()) {
1101       *error_msg = StringPrintf(
1102           "Mismatched catch handler type for code item at offset %x: %u vs %u.",
1103           orig_offset,
1104           orig_handler->GetTypeId()->GetIndex(),
1105           output_handler->GetTypeId()->GetIndex());
1106       return false;
1107     }
1108     if (orig_handler->GetAddress() != output_handler->GetAddress()) {
1109       *error_msg = StringPrintf(
1110           "Mismatched catch handler address for code item at offset %x: %u vs %u.",
1111           orig_offset,
1112           orig_handler->GetAddress(),
1113           output_handler->GetAddress());
1114       return false;
1115     }
1116   }
1117   return true;
1118 }
1119 
1120 }  // namespace art
1121