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
27namespace art {
28
29using android::base::StringPrintf;
30
31bool 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
52template<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
69bool 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
81bool 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
93bool 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
118bool 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
147bool 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
176struct ClassDefCompare {
177  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.
184bool 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
211bool 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
266bool 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
283bool 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
314bool 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
355bool 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
396bool 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
437bool 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
458bool 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
485bool 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
501bool 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
534bool 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
549bool 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
701bool 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
731bool 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
760bool 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
793bool 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
829bool 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
886bool 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
908bool 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
940bool 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
1002bool 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
1049bool 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
1076bool 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