Home | History | Annotate | Download | only in dexlayout
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 {
    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.
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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   // TODO: Test for debug equivalence rather than byte array equality.
    897   uint32_t orig_size = orig->GetDebugInfoSize();
    898   uint32_t output_size = output->GetDebugInfoSize();
    899   if (orig_size != output_size) {
    900     *error_msg = "DebugInfoSize disagreed.";
    901     return false;
    902   }
    903   uint8_t* orig_data = orig->GetDebugInfo();
    904   uint8_t* output_data = output->GetDebugInfo();
    905   if ((orig_data == nullptr && output_data != nullptr) ||
    906       (orig_data != nullptr && output_data == nullptr)) {
    907     *error_msg = "DebugInfo null/non-null mismatch.";
    908     return false;
    909   }
    910   if (memcmp(orig_data, output_data, orig_size) != 0) {
    911     *error_msg = "DebugInfo bytes mismatch.";
    912     return false;
    913   }
    914   return true;
    915 }
    916 
    917 bool VerifyTries(dex_ir::TryItemVector* orig,
    918                  dex_ir::TryItemVector* output,
    919                  uint32_t orig_offset,
    920                  std::string* error_msg) {
    921   if (orig == nullptr || output == nullptr) {
    922     if (orig != output) {
    923       *error_msg = "Found unexpected empty try items.";
    924       return false;
    925     }
    926     return true;
    927   }
    928   if (orig->size() != output->size()) {
    929     *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %zu vs %zu.",
    930                               orig_offset,
    931                               orig->size(),
    932                               output->size());
    933     return false;
    934   }
    935   for (size_t i = 0; i < orig->size(); ++i) {
    936     const dex_ir::TryItem* orig_try = (*orig)[i].get();
    937     const dex_ir::TryItem* output_try = (*output)[i].get();
    938     if (orig_try->StartAddr() != output_try->StartAddr()) {
    939       *error_msg = StringPrintf(
    940           "Mismatched try item start addr for code item at offset %x: %u vs %u.",
    941           orig_offset,
    942           orig_try->StartAddr(),
    943           output_try->StartAddr());
    944       return false;
    945     }
    946     if (orig_try->InsnCount() != output_try->InsnCount()) {
    947       *error_msg = StringPrintf(
    948           "Mismatched try item insn count for code item at offset %x: %u vs %u.",
    949           orig_offset,
    950           orig_try->InsnCount(),
    951                                 output_try->InsnCount());
    952       return false;
    953     }
    954     if (!VerifyHandler(orig_try->GetHandlers(),
    955                        output_try->GetHandlers(),
    956                        orig_offset,
    957                        error_msg)) {
    958       return false;
    959     }
    960   }
    961   return true;
    962 }
    963 
    964 bool VerifyHandlers(dex_ir::CatchHandlerVector* orig,
    965                     dex_ir::CatchHandlerVector* output,
    966                     uint32_t orig_offset,
    967                     std::string* error_msg) {
    968   if (orig == nullptr || output == nullptr) {
    969     if (orig != output) {
    970       *error_msg = "Found unexpected empty catch handlers.";
    971       return false;
    972     }
    973     return true;
    974   }
    975   if (orig->size() != output->size()) {
    976     *error_msg = StringPrintf(
    977         "Mismatched catch handlers size for code item at offset %x: %zu vs %zu.",
    978         orig_offset,
    979         orig->size(),
    980         output->size());
    981     return false;
    982   }
    983   for (size_t i = 0; i < orig->size(); ++i) {
    984     if (!VerifyHandler((*orig)[i].get(), (*output)[i].get(), orig_offset, error_msg)) {
    985       return false;
    986     }
    987   }
    988   return true;
    989 }
    990 
    991 bool VerifyHandler(const dex_ir::CatchHandler* orig,
    992                    const dex_ir::CatchHandler* output,
    993                    uint32_t orig_offset,
    994                    std::string* error_msg) {
    995   dex_ir::TypeAddrPairVector* orig_handlers = orig->GetHandlers();
    996   dex_ir::TypeAddrPairVector* output_handlers = output->GetHandlers();
    997   if (orig_handlers->size() != output_handlers->size()) {
    998     *error_msg = StringPrintf(
    999         "Mismatched number of catch handlers for code item at offset %x: %zu vs %zu.",
   1000         orig_offset,
   1001         orig_handlers->size(),
   1002         output_handlers->size());
   1003     return false;
   1004   }
   1005   for (size_t i = 0; i < orig_handlers->size(); ++i) {
   1006     const dex_ir::TypeAddrPair* orig_handler = (*orig_handlers)[i].get();
   1007     const dex_ir::TypeAddrPair* output_handler = (*output_handlers)[i].get();
   1008     if (orig_handler->GetTypeId() == nullptr || output_handler->GetTypeId() == nullptr) {
   1009       if (orig_handler->GetTypeId() != output_handler->GetTypeId()) {
   1010         *error_msg = StringPrintf(
   1011             "Found unexpected catch all catch handler for code item at offset %x.",
   1012             orig_offset);
   1013         return false;
   1014       }
   1015     } else if (orig_handler->GetTypeId()->GetIndex() != output_handler->GetTypeId()->GetIndex()) {
   1016       *error_msg = StringPrintf(
   1017           "Mismatched catch handler type for code item at offset %x: %u vs %u.",
   1018           orig_offset,
   1019           orig_handler->GetTypeId()->GetIndex(),
   1020           output_handler->GetTypeId()->GetIndex());
   1021       return false;
   1022     }
   1023     if (orig_handler->GetAddress() != output_handler->GetAddress()) {
   1024       *error_msg = StringPrintf(
   1025           "Mismatched catch handler address for code item at offset %x: %u vs %u.",
   1026           orig_offset,
   1027           orig_handler->GetAddress(),
   1028           output_handler->GetAddress());
   1029       return false;
   1030     }
   1031   }
   1032   return true;
   1033 }
   1034 
   1035 }  // namespace art
   1036